25 |
33 |
26 |
34 |
27 class AdBlockSubscription(QObject): |
35 class AdBlockSubscription(QObject): |
28 """ |
36 """ |
29 Class implementing the AdBlock subscription. |
37 Class implementing the AdBlock subscription. |
30 |
38 |
31 @signal changed() emitted after the subscription has changed |
39 @signal changed() emitted after the subscription has changed |
32 @signal rulesChanged() emitted after the subscription's rules have changed |
40 @signal rulesChanged() emitted after the subscription's rules have changed |
33 @signal enabledChanged(bool) emitted after the enabled state was changed |
41 @signal enabledChanged(bool) emitted after the enabled state was changed |
34 @signal rulesEnabledChanged() emitted after a rule enabled state was |
42 @signal rulesEnabledChanged() emitted after a rule enabled state was |
35 changed |
43 changed |
36 """ |
44 """ |
|
45 |
37 changed = pyqtSignal() |
46 changed = pyqtSignal() |
38 rulesChanged = pyqtSignal() |
47 rulesChanged = pyqtSignal() |
39 enabledChanged = pyqtSignal(bool) |
48 enabledChanged = pyqtSignal(bool) |
40 rulesEnabledChanged = pyqtSignal() |
49 rulesEnabledChanged = pyqtSignal() |
41 |
50 |
42 def __init__(self, url, custom, parent=None, default=False): |
51 def __init__(self, url, custom, parent=None, default=False): |
43 """ |
52 """ |
44 Constructor |
53 Constructor |
45 |
54 |
46 @param url AdBlock URL for the subscription (QUrl) |
55 @param url AdBlock URL for the subscription (QUrl) |
47 @param custom flag indicating a custom subscription (boolean) |
56 @param custom flag indicating a custom subscription (boolean) |
48 @param parent reference to the parent object (QObject) |
57 @param parent reference to the parent object (QObject) |
49 @param default flag indicating a default subscription (boolean) |
58 @param default flag indicating a default subscription (boolean) |
50 """ |
59 """ |
51 super().__init__(parent) |
60 super().__init__(parent) |
52 |
61 |
53 self.__custom = custom |
62 self.__custom = custom |
54 self.__url = url.toEncoded() |
63 self.__url = url.toEncoded() |
55 self.__enabled = False |
64 self.__enabled = False |
56 self.__downloading = None |
65 self.__downloading = None |
57 self.__defaultSubscription = default |
66 self.__defaultSubscription = default |
58 |
67 |
59 self.__title = "" |
68 self.__title = "" |
60 self.__location = QByteArray() |
69 self.__location = QByteArray() |
61 self.__lastUpdate = QDateTime() |
70 self.__lastUpdate = QDateTime() |
62 self.__requiresLocation = "" |
71 self.__requiresLocation = "" |
63 self.__requiresTitle = "" |
72 self.__requiresTitle = "" |
64 |
73 |
65 self.__updatePeriod = 0 # update period in hours, 0 = use default |
74 self.__updatePeriod = 0 # update period in hours, 0 = use default |
66 self.__remoteModified = QDateTime() |
75 self.__remoteModified = QDateTime() |
67 |
76 |
68 self.__rules = [] # list containing all AdBlock rules |
77 self.__rules = [] # list containing all AdBlock rules |
69 |
78 |
70 self.__checksumRe = re.compile( |
79 self.__checksumRe = re.compile( |
71 r"""^\s*!\s*checksum[\s\-:]+([\w\+\/=]+).*\n""", |
80 r"""^\s*!\s*checksum[\s\-:]+([\w\+\/=]+).*\n""", |
72 re.IGNORECASE | re.MULTILINE) |
81 re.IGNORECASE | re.MULTILINE, |
|
82 ) |
73 self.__expiresRe = re.compile( |
83 self.__expiresRe = re.compile( |
74 r"""(?:expires:|expires after)\s*(\d+)\s*(hour|h)?""", |
84 r"""(?:expires:|expires after)\s*(\d+)\s*(hour|h)?""", re.IGNORECASE |
75 re.IGNORECASE) |
85 ) |
76 self.__remoteModifiedRe = re.compile( |
86 self.__remoteModifiedRe = re.compile( |
77 r"""!\s*(?:Last modified|Updated):\s*(\d{1,2})\s*""" |
87 r"""!\s*(?:Last modified|Updated):\s*(\d{1,2})\s*""" |
78 r"""(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s*""" |
88 r"""(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s*""" |
79 r"""(\d{2,4})\s*((\d{1,2}):(\d{2}))?""", |
89 r"""(\d{2,4})\s*((\d{1,2}):(\d{2}))?""", |
80 re.IGNORECASE) |
90 re.IGNORECASE, |
81 |
91 ) |
|
92 |
82 self.__monthNameToNumber = { |
93 self.__monthNameToNumber = { |
83 "Jan": 1, |
94 "Jan": 1, |
84 "Feb": 2, |
95 "Feb": 2, |
85 "Mar": 3, |
96 "Mar": 3, |
86 "Apr": 4, |
97 "Apr": 4, |
89 "Jul": 7, |
100 "Jul": 7, |
90 "Aug": 8, |
101 "Aug": 8, |
91 "Sep": 9, |
102 "Sep": 9, |
92 "Oct": 10, |
103 "Oct": 10, |
93 "Nov": 11, |
104 "Nov": 11, |
94 "Dec": 12 |
105 "Dec": 12, |
95 } |
106 } |
96 |
107 |
97 self.__parseUrl(url) |
108 self.__parseUrl(url) |
98 |
109 |
99 def __parseUrl(self, url): |
110 def __parseUrl(self, url): |
100 """ |
111 """ |
101 Private method to parse the AdBlock URL for the subscription. |
112 Private method to parse the AdBlock URL for the subscription. |
102 |
113 |
103 @param url AdBlock URL for the subscription |
114 @param url AdBlock URL for the subscription |
104 @type QUrl |
115 @type QUrl |
105 """ |
116 """ |
106 if url.scheme() != "abp": |
117 if url.scheme() != "abp": |
107 return |
118 return |
108 |
119 |
109 if url.path() != "subscribe": |
120 if url.path() != "subscribe": |
110 return |
121 return |
111 |
122 |
112 urlQuery = QUrlQuery(url) |
123 urlQuery = QUrlQuery(url) |
113 self.__title = QUrl.fromPercentEncoding( |
124 self.__title = QUrl.fromPercentEncoding( |
114 QByteArray(urlQuery.queryItemValue("title").encode())) |
125 QByteArray(urlQuery.queryItemValue("title").encode()) |
|
126 ) |
115 self.__enabled = urlQuery.queryItemValue("enabled") != "false" |
127 self.__enabled = urlQuery.queryItemValue("enabled") != "false" |
116 self.__location = QByteArray(QUrl.fromPercentEncoding( |
128 self.__location = QByteArray( |
117 QByteArray(urlQuery.queryItemValue("location").encode())) |
129 QUrl.fromPercentEncoding( |
118 .encode("utf-8")) |
130 QByteArray(urlQuery.queryItemValue("location").encode()) |
119 |
131 ).encode("utf-8") |
|
132 ) |
|
133 |
120 # Check for required subscription |
134 # Check for required subscription |
121 self.__requiresLocation = QUrl.fromPercentEncoding( |
135 self.__requiresLocation = QUrl.fromPercentEncoding( |
122 QByteArray(urlQuery.queryItemValue( |
136 QByteArray(urlQuery.queryItemValue("requiresLocation").encode()) |
123 "requiresLocation").encode())) |
137 ) |
124 self.__requiresTitle = QUrl.fromPercentEncoding( |
138 self.__requiresTitle = QUrl.fromPercentEncoding( |
125 QByteArray(urlQuery.queryItemValue("requiresTitle").encode())) |
139 QByteArray(urlQuery.queryItemValue("requiresTitle").encode()) |
|
140 ) |
126 if self.__requiresLocation and self.__requiresTitle: |
141 if self.__requiresLocation and self.__requiresTitle: |
127 from WebBrowser.WebBrowserWindow import WebBrowserWindow |
142 from WebBrowser.WebBrowserWindow import WebBrowserWindow |
|
143 |
128 WebBrowserWindow.adBlockManager().loadRequiredSubscription( |
144 WebBrowserWindow.adBlockManager().loadRequiredSubscription( |
129 self.__requiresLocation, self.__requiresTitle) |
145 self.__requiresLocation, self.__requiresTitle |
130 |
146 ) |
|
147 |
131 lastUpdateString = urlQuery.queryItemValue("lastUpdate") |
148 lastUpdateString = urlQuery.queryItemValue("lastUpdate") |
132 self.__lastUpdate = QDateTime.fromString(lastUpdateString, |
149 self.__lastUpdate = QDateTime.fromString( |
133 Qt.DateFormat.ISODate) |
150 lastUpdateString, Qt.DateFormat.ISODate |
134 |
151 ) |
|
152 |
135 self.__loadRules() |
153 self.__loadRules() |
136 |
154 |
137 def url(self): |
155 def url(self): |
138 """ |
156 """ |
139 Public method to generate the URL for this subscription. |
157 Public method to generate the URL for this subscription. |
140 |
158 |
141 @return AdBlock URL for the subscription |
159 @return AdBlock URL for the subscription |
142 @rtype QUrl |
160 @rtype QUrl |
143 """ |
161 """ |
144 url = QUrl() |
162 url = QUrl() |
145 url.setScheme("abp") |
163 url.setScheme("abp") |
146 url.setPath("subscribe") |
164 url.setPath("subscribe") |
147 |
165 |
148 queryItems = [] |
166 queryItems = [] |
149 queryItems.append(("location", bytes(self.__location).decode())) |
167 queryItems.append(("location", bytes(self.__location).decode())) |
150 queryItems.append(("title", self.__title)) |
168 queryItems.append(("title", self.__title)) |
151 if self.__requiresLocation and self.__requiresTitle: |
169 if self.__requiresLocation and self.__requiresTitle: |
152 queryItems.append(("requiresLocation", self.__requiresLocation)) |
170 queryItems.append(("requiresLocation", self.__requiresLocation)) |
153 queryItems.append(("requiresTitle", self.__requiresTitle)) |
171 queryItems.append(("requiresTitle", self.__requiresTitle)) |
154 if not self.__enabled: |
172 if not self.__enabled: |
155 queryItems.append(("enabled", "false")) |
173 queryItems.append(("enabled", "false")) |
156 if self.__lastUpdate.isValid(): |
174 if self.__lastUpdate.isValid(): |
157 queryItems.append( |
175 queryItems.append( |
158 ("lastUpdate", |
176 ("lastUpdate", self.__lastUpdate.toString(Qt.DateFormat.ISODate)) |
159 self.__lastUpdate.toString(Qt.DateFormat.ISODate)) |
|
160 ) |
177 ) |
161 |
178 |
162 query = QUrlQuery() |
179 query = QUrlQuery() |
163 query.setQueryItems(queryItems) |
180 query.setQueryItems(queryItems) |
164 url.setQuery(query) |
181 url.setQuery(query) |
165 return url |
182 return url |
166 |
183 |
167 def isEnabled(self): |
184 def isEnabled(self): |
168 """ |
185 """ |
169 Public method to check, if the subscription is enabled. |
186 Public method to check, if the subscription is enabled. |
170 |
187 |
171 @return flag indicating the enabled status |
188 @return flag indicating the enabled status |
172 @rtype bool |
189 @rtype bool |
173 """ |
190 """ |
174 return self.__enabled |
191 return self.__enabled |
175 |
192 |
176 def setEnabled(self, enabled): |
193 def setEnabled(self, enabled): |
177 """ |
194 """ |
178 Public method to set the enabled status. |
195 Public method to set the enabled status. |
179 |
196 |
180 @param enabled flag indicating the enabled status |
197 @param enabled flag indicating the enabled status |
181 @type bool |
198 @type bool |
182 """ |
199 """ |
183 if self.__enabled == enabled: |
200 if self.__enabled == enabled: |
184 return |
201 return |
185 |
202 |
186 self.__enabled = enabled |
203 self.__enabled = enabled |
187 self.enabledChanged.emit(enabled) |
204 self.enabledChanged.emit(enabled) |
188 |
205 |
189 def title(self): |
206 def title(self): |
190 """ |
207 """ |
191 Public method to get the subscription title. |
208 Public method to get the subscription title. |
192 |
209 |
193 @return subscription title |
210 @return subscription title |
194 @rtype string |
211 @rtype string |
195 """ |
212 """ |
196 return self.__title |
213 return self.__title |
197 |
214 |
198 def setTitle(self, title): |
215 def setTitle(self, title): |
199 """ |
216 """ |
200 Public method to set the subscription title. |
217 Public method to set the subscription title. |
201 |
218 |
202 @param title subscription title |
219 @param title subscription title |
203 @type str |
220 @type str |
204 """ |
221 """ |
205 if self.__title == title: |
222 if self.__title == title: |
206 return |
223 return |
207 |
224 |
208 self.__title = title |
225 self.__title = title |
209 self.changed.emit() |
226 self.changed.emit() |
210 |
227 |
211 def location(self): |
228 def location(self): |
212 """ |
229 """ |
213 Public method to get the subscription location. |
230 Public method to get the subscription location. |
214 |
231 |
215 @return URL of the subscription location |
232 @return URL of the subscription location |
216 @rtype QUrl |
233 @rtype QUrl |
217 """ |
234 """ |
218 return QUrl.fromEncoded(self.__location) |
235 return QUrl.fromEncoded(self.__location) |
219 |
236 |
220 def setLocation(self, url): |
237 def setLocation(self, url): |
221 """ |
238 """ |
222 Public method to set the subscription location. |
239 Public method to set the subscription location. |
223 |
240 |
224 @param url URL of the subscription location |
241 @param url URL of the subscription location |
225 @type QUrl |
242 @type QUrl |
226 """ |
243 """ |
227 if url == self.location(): |
244 if url == self.location(): |
228 return |
245 return |
229 |
246 |
230 self.__location = url.toEncoded() |
247 self.__location = url.toEncoded() |
231 self.__lastUpdate = QDateTime() |
248 self.__lastUpdate = QDateTime() |
232 self.changed.emit() |
249 self.changed.emit() |
233 |
250 |
234 def requiresLocation(self): |
251 def requiresLocation(self): |
235 """ |
252 """ |
236 Public method to get the location of a required subscription. |
253 Public method to get the location of a required subscription. |
237 |
254 |
238 @return location of a required subscription |
255 @return location of a required subscription |
239 @rtype str |
256 @rtype str |
240 """ |
257 """ |
241 return self.__requiresLocation |
258 return self.__requiresLocation |
242 |
259 |
243 def lastUpdate(self): |
260 def lastUpdate(self): |
244 """ |
261 """ |
245 Public method to get the date and time of the last update. |
262 Public method to get the date and time of the last update. |
246 |
263 |
247 @return date and time of the last update |
264 @return date and time of the last update |
248 @rtype QDateTime |
265 @rtype QDateTime |
249 """ |
266 """ |
250 return self.__lastUpdate |
267 return self.__lastUpdate |
251 |
268 |
252 def rulesFileName(self): |
269 def rulesFileName(self): |
253 """ |
270 """ |
254 Public method to get the name of the rules file. |
271 Public method to get the name of the rules file. |
255 |
272 |
256 @return name of the rules file |
273 @return name of the rules file |
257 @rtype str |
274 @rtype str |
258 """ |
275 """ |
259 if self.location().scheme() == "file": |
276 if self.location().scheme() == "file": |
260 return self.location().toLocalFile() |
277 return self.location().toLocalFile() |
261 |
278 |
262 if self.__location.isEmpty(): |
279 if self.__location.isEmpty(): |
263 return "" |
280 return "" |
264 |
281 |
265 sha1 = bytes(QCryptographicHash.hash( |
282 sha1 = bytes( |
266 self.__location, QCryptographicHash.Algorithm.Sha1).toHex() |
283 QCryptographicHash.hash( |
|
284 self.__location, QCryptographicHash.Algorithm.Sha1 |
|
285 ).toHex() |
267 ).decode() |
286 ).decode() |
268 dataDir = os.path.join( |
287 dataDir = os.path.join(Utilities.getConfigDir(), "web_browser", "subscriptions") |
269 Utilities.getConfigDir(), "web_browser", "subscriptions") |
|
270 if not os.path.exists(dataDir): |
288 if not os.path.exists(dataDir): |
271 os.makedirs(dataDir) |
289 os.makedirs(dataDir) |
272 fileName = os.path.join( |
290 fileName = os.path.join(dataDir, "adblock_subscription_{0}".format(sha1)) |
273 dataDir, "adblock_subscription_{0}".format(sha1)) |
|
274 return fileName |
291 return fileName |
275 |
292 |
276 def __loadRules(self): |
293 def __loadRules(self): |
277 """ |
294 """ |
278 Private method to load the rules of the subscription. |
295 Private method to load the rules of the subscription. |
279 """ |
296 """ |
280 fileName = self.rulesFileName() |
297 fileName = self.rulesFileName() |
311 # hours |
330 # hours |
312 self.__updatePeriod = int(period) |
331 self.__updatePeriod = int(period) |
313 else: |
332 else: |
314 # days |
333 # days |
315 self.__updatePeriod = int(period) * 24 |
334 self.__updatePeriod = int(period) * 24 |
316 remoteModified = self.__remoteModifiedRe.search( |
335 remoteModified = self.__remoteModifiedRe.search(line) |
317 line) |
|
318 if remoteModified: |
336 if remoteModified: |
319 day, month, year, time, hour, minute = ( |
337 ( |
320 remoteModified.groups() |
338 day, |
321 ) |
339 month, |
|
340 year, |
|
341 time, |
|
342 hour, |
|
343 minute, |
|
344 ) = remoteModified.groups() |
322 self.__remoteModified.setDate( |
345 self.__remoteModified.setDate( |
323 QDate(int(year), |
346 QDate( |
324 self.__monthNameToNumber[month], |
347 int(year), |
325 int(day)) |
348 self.__monthNameToNumber[month], |
|
349 int(day), |
|
350 ) |
326 ) |
351 ) |
327 if time: |
352 if time: |
328 self.__remoteModified.setTime( |
353 self.__remoteModified.setTime( |
329 QTime(int(hour), int(minute))) |
354 QTime(int(hour), int(minute)) |
|
355 ) |
330 else: |
356 else: |
331 # no time given, set it to 23:59 |
357 # no time given, set it to 23:59 |
332 self.__remoteModified.setTime( |
358 self.__remoteModified.setTime(QTime(23, 59)) |
333 QTime(23, 59)) |
|
334 self.changed.emit() |
359 self.changed.emit() |
335 except OSError as err: |
360 except OSError as err: |
336 EricMessageBox.warning( |
361 EricMessageBox.warning( |
337 None, |
362 None, |
338 self.tr("Load subscription rules"), |
363 self.tr("Load subscription rules"), |
339 self.tr( |
364 self.tr( |
340 """Unable to read AdBlock file '{0}'.\nReason: {1}""") |
365 """Unable to read AdBlock file '{0}'.\nReason: {1}""" |
341 .format(fileName, str(err)) |
366 ).format(fileName, str(err)), |
342 ) |
367 ) |
343 |
368 |
344 elif not fileName.endswith("_custom"): |
369 elif not fileName.endswith("_custom"): |
345 self.__lastUpdate = QDateTime() |
370 self.__lastUpdate = QDateTime() |
346 |
371 |
347 self.checkForUpdate() |
372 self.checkForUpdate() |
348 |
373 |
349 def checkForUpdate(self): |
374 def checkForUpdate(self): |
350 """ |
375 """ |
351 Public method to check for an update. |
376 Public method to check for an update. |
352 """ |
377 """ |
353 updatePeriod = ( |
378 updatePeriod = ( |
354 self.__updatePeriod |
379 self.__updatePeriod |
355 if self.__updatePeriod else |
380 if self.__updatePeriod |
356 Preferences.getWebBrowser("AdBlockUpdatePeriod") * 24 |
381 else Preferences.getWebBrowser("AdBlockUpdatePeriod") * 24 |
357 ) |
382 ) |
358 if ( |
383 if ( |
359 not self.__lastUpdate.isValid() or |
384 not self.__lastUpdate.isValid() |
360 (self.__remoteModified.isValid() and |
385 or ( |
361 self.__remoteModified.addSecs(updatePeriod * 3600) < |
386 self.__remoteModified.isValid() |
362 QDateTime.currentDateTime()) or |
387 and self.__remoteModified.addSecs(updatePeriod * 3600) |
363 self.__lastUpdate.addSecs(updatePeriod * 3600) < |
388 < QDateTime.currentDateTime() |
364 QDateTime.currentDateTime() |
389 ) |
|
390 or self.__lastUpdate.addSecs(updatePeriod * 3600) |
|
391 < QDateTime.currentDateTime() |
365 ): |
392 ): |
366 self.updateNow() |
393 self.updateNow() |
367 |
394 |
368 def updateNow(self): |
395 def updateNow(self): |
369 """ |
396 """ |
370 Public method to update the subscription immediately. |
397 Public method to update the subscription immediately. |
371 """ |
398 """ |
372 if self.__downloading is not None: |
399 if self.__downloading is not None: |
373 return |
400 return |
374 |
401 |
375 if not self.location().isValid(): |
402 if not self.location().isValid(): |
376 return |
403 return |
377 |
404 |
378 if self.location().scheme() == "file": |
405 if self.location().scheme() == "file": |
379 self.__lastUpdate = QDateTime.currentDateTime() |
406 self.__lastUpdate = QDateTime.currentDateTime() |
380 self.__loadRules() |
407 self.__loadRules() |
381 return |
408 return |
382 |
409 |
383 from WebBrowser.WebBrowserWindow import WebBrowserWindow |
410 from WebBrowser.WebBrowserWindow import WebBrowserWindow |
384 reply = WebBrowserWindow.networkManager().get( |
411 |
385 QNetworkRequest(self.location())) |
412 reply = WebBrowserWindow.networkManager().get(QNetworkRequest(self.location())) |
386 reply.finished.connect( |
413 reply.finished.connect(lambda: self.__rulesDownloaded(reply)) |
387 lambda: self.__rulesDownloaded(reply)) |
|
388 self.__downloading = reply |
414 self.__downloading = reply |
389 |
415 |
390 def __rulesDownloaded(self, reply): |
416 def __rulesDownloaded(self, reply): |
391 """ |
417 """ |
392 Private slot to deal with the downloaded rules. |
418 Private slot to deal with the downloaded rules. |
393 |
419 |
394 @param reply reference to the network reply |
420 @param reply reference to the network reply |
395 @type QNetworkReply |
421 @type QNetworkReply |
396 """ |
422 """ |
397 response = bytes(reply.readAll()) |
423 response = bytes(reply.readAll()) |
398 reply.close() |
424 reply.close() |
399 self.__downloading = None |
425 self.__downloading = None |
400 |
426 |
401 if reply.error() != QNetworkReply.NetworkError.NoError: |
427 if reply.error() != QNetworkReply.NetworkError.NoError: |
402 if not self.__defaultSubscription: |
428 if not self.__defaultSubscription: |
403 # don't show error if we try to load the default |
429 # don't show error if we try to load the default |
404 EricMessageBox.warning( |
430 EricMessageBox.warning( |
405 None, |
431 None, |
406 self.tr("Downloading subscription rules"), |
432 self.tr("Downloading subscription rules"), |
407 self.tr( |
433 self.tr( |
408 """<p>Subscription rules could not be""" |
434 """<p>Subscription rules could not be""" |
409 """ downloaded.</p><p>Error: {0}</p>""") |
435 """ downloaded.</p><p>Error: {0}</p>""" |
410 .format(reply.errorString())) |
436 ).format(reply.errorString()), |
|
437 ) |
411 else: |
438 else: |
412 # reset after first download attempt |
439 # reset after first download attempt |
413 self.__defaultSubscription = False |
440 self.__defaultSubscription = False |
414 return |
441 return |
415 |
442 |
416 if not response: |
443 if not response: |
417 EricMessageBox.warning( |
444 EricMessageBox.warning( |
418 None, |
445 None, |
419 self.tr("Downloading subscription rules"), |
446 self.tr("Downloading subscription rules"), |
420 self.tr("""Got empty subscription rules.""")) |
447 self.tr("""Got empty subscription rules."""), |
421 return |
448 ) |
422 |
449 return |
|
450 |
423 fileName = self.rulesFileName() |
451 fileName = self.rulesFileName() |
424 try: |
452 try: |
425 with open(fileName, "wb") as f: |
453 with open(fileName, "wb") as f: |
426 from WebBrowser.WebBrowserWindow import WebBrowserWindow |
454 from WebBrowser.WebBrowserWindow import WebBrowserWindow |
|
455 |
427 if ( |
456 if ( |
428 WebBrowserWindow.adBlockManager().useLimitedEasyList() and |
457 WebBrowserWindow.adBlockManager().useLimitedEasyList() |
429 self.url().toString().startswith( |
458 and self.url() |
430 WebBrowserWindow.adBlockManager() |
459 .toString() |
431 .getDefaultSubscriptionUrl()) |
460 .startswith( |
|
461 WebBrowserWindow.adBlockManager().getDefaultSubscriptionUrl() |
|
462 ) |
432 ): |
463 ): |
433 limited = True |
464 limited = True |
434 # ignore Third-party advertisers rules for performance |
465 # ignore Third-party advertisers rules for performance |
435 # whitelist rules at the end will be used |
466 # whitelist rules at the end will be used |
436 index = response.find( |
467 index = response.find( |
437 b"!---------------------------" |
468 b"!---------------------------" |
438 b"Third-party advertisers" |
469 b"Third-party advertisers" |
439 b"---------------------------!") |
470 b"---------------------------!" |
|
471 ) |
440 part1 = response[:index] |
472 part1 = response[:index] |
441 index = response.find( |
473 index = response.find( |
442 b"!-----------------------" |
474 b"!-----------------------" |
443 b"Whitelists to fix broken sites" |
475 b"Whitelists to fix broken sites" |
444 b"------------------------!") |
476 b"------------------------!" |
|
477 ) |
445 part2 = response[index:] |
478 part2 = response[index:] |
446 f.write(part1) |
479 f.write(part1) |
447 f.write(part2) |
480 f.write(part2) |
448 else: |
481 else: |
449 limited = False |
482 limited = False |
450 f.write(response) |
483 f.write(response) |
451 f.close() |
484 f.close() |
452 self.__lastUpdate = QDateTime.currentDateTime() |
485 self.__lastUpdate = QDateTime.currentDateTime() |
453 |
486 |
454 if limited or self.__validateCheckSum(fileName): |
487 if limited or self.__validateCheckSum(fileName): |
455 self.__loadRules() |
488 self.__loadRules() |
456 else: |
489 else: |
457 os.unlink(fileName) |
490 os.unlink(fileName) |
458 except OSError: |
491 except OSError: |
459 EricMessageBox.warning( |
492 EricMessageBox.warning( |
460 None, |
493 None, |
461 self.tr("Downloading subscription rules"), |
494 self.tr("Downloading subscription rules"), |
462 self.tr("""Unable to write to AdBlock file '{0}'.""") |
495 self.tr("""Unable to write to AdBlock file '{0}'.""").file(fileName), |
463 .file(fileName)) |
496 ) |
464 self.__downloading = None |
497 self.__downloading = None |
465 reply.deleteLater() |
498 reply.deleteLater() |
466 |
499 |
467 def __validateCheckSum(self, fileName): |
500 def __validateCheckSum(self, fileName): |
468 """ |
501 """ |
469 Private method to check the subscription file's checksum. |
502 Private method to check the subscription file's checksum. |
470 |
503 |
471 @param fileName name of the file containing the subscription |
504 @param fileName name of the file containing the subscription |
472 @type str |
505 @type str |
473 @return flag indicating a valid file. A file is considered |
506 @return flag indicating a valid file. A file is considered |
474 valid, if the checksum is OK, the file does not contain a |
507 valid, if the checksum is OK, the file does not contain a |
475 checksum (i.e. cannot be checked) or we are using the limited |
508 checksum (i.e. cannot be checked) or we are using the limited |
509 self.tr( |
540 self.tr( |
510 """<p>AdBlock subscription <b>{0}</b> has a wrong""" |
541 """<p>AdBlock subscription <b>{0}</b> has a wrong""" |
511 """ checksum.<br/>""" |
542 """ checksum.<br/>""" |
512 """Found: {1}<br/>""" |
543 """Found: {1}<br/>""" |
513 """Calculated: {2}<br/>""" |
544 """Calculated: {2}<br/>""" |
514 """Use it anyway?</p>""") |
545 """Use it anyway?</p>""" |
515 .format(self.__title, expectedChecksum, |
546 ).format(self.__title, expectedChecksum, calculatedChecksum), |
516 calculatedChecksum)) |
547 ) |
517 return res |
548 return res |
518 |
549 |
519 def saveRules(self): |
550 def saveRules(self): |
520 """ |
551 """ |
521 Public method to save the subscription rules. |
552 Public method to save the subscription rules. |
522 """ |
553 """ |
523 fileName = self.rulesFileName() |
554 fileName = self.rulesFileName() |
524 if not fileName: |
555 if not fileName: |
525 return |
556 return |
526 |
557 |
527 try: |
558 try: |
528 with open(fileName, "w", encoding="utf-8") as f: |
559 with open(fileName, "w", encoding="utf-8") as f: |
529 if not self.__rules or not self.__rules[0].isHeader(): |
560 if not self.__rules or not self.__rules[0].isHeader(): |
530 f.write("[Adblock Plus 2.0]\n") |
561 f.write("[Adblock Plus 2.0]\n") |
531 for rule in self.__rules: |
562 for rule in self.__rules: |
532 f.write(rule.filter() + "\n") |
563 f.write(rule.filter() + "\n") |
533 except OSError: |
564 except OSError: |
534 EricMessageBox.warning( |
565 EricMessageBox.warning( |
535 None, |
566 None, |
536 self.tr("Saving subscription rules"), |
567 self.tr("Saving subscription rules"), |
537 self.tr("""Unable to write to AdBlock file '{0}'.""") |
568 self.tr("""Unable to write to AdBlock file '{0}'.""").format(fileName), |
538 .format(fileName)) |
569 ) |
539 |
570 |
540 def rule(self, offset): |
571 def rule(self, offset): |
541 """ |
572 """ |
542 Public method to get a specific rule. |
573 Public method to get a specific rule. |
543 |
574 |
544 @param offset offset of the rule |
575 @param offset offset of the rule |
545 @type int |
576 @type int |
546 @return requested rule |
577 @return requested rule |
547 @rtype AdBlockRule |
578 @rtype AdBlockRule |
548 """ |
579 """ |
549 if offset >= len(self.__rules): |
580 if offset >= len(self.__rules): |
550 return None |
581 return None |
551 |
582 |
552 return self.__rules[offset] |
583 return self.__rules[offset] |
553 |
584 |
554 def allRules(self): |
585 def allRules(self): |
555 """ |
586 """ |
556 Public method to get the list of rules. |
587 Public method to get the list of rules. |
557 |
588 |
558 @return list of rules |
589 @return list of rules |
559 @rtype list of AdBlockRule |
590 @rtype list of AdBlockRule |
560 """ |
591 """ |
561 return self.__rules[:] |
592 return self.__rules[:] |
562 |
593 |
563 def addRule(self, rule): |
594 def addRule(self, rule): |
564 """ |
595 """ |
565 Public method to add a rule. |
596 Public method to add a rule. |
566 |
597 |
567 @param rule reference to the rule to add |
598 @param rule reference to the rule to add |
568 @type AdBlockRule |
599 @type AdBlockRule |
569 @return offset of the rule |
600 @return offset of the rule |
570 @rtype int |
601 @rtype int |
571 """ |
602 """ |
572 self.__rules.append(rule) |
603 self.__rules.append(rule) |
573 self.rulesChanged.emit() |
604 self.rulesChanged.emit() |
574 |
605 |
575 return len(self.__rules) - 1 |
606 return len(self.__rules) - 1 |
576 |
607 |
577 def removeRule(self, offset): |
608 def removeRule(self, offset): |
578 """ |
609 """ |
579 Public method to remove a rule given the offset. |
610 Public method to remove a rule given the offset. |
580 |
611 |
581 @param offset offset of the rule to remove |
612 @param offset offset of the rule to remove |
582 @type int |
613 @type int |
583 """ |
614 """ |
584 if offset < 0 or offset > len(self.__rules): |
615 if offset < 0 or offset > len(self.__rules): |
585 return |
616 return |
586 |
617 |
587 del self.__rules[offset] |
618 del self.__rules[offset] |
588 self.rulesChanged.emit() |
619 self.rulesChanged.emit() |
589 |
620 |
590 def replaceRule(self, rule, offset): |
621 def replaceRule(self, rule, offset): |
591 """ |
622 """ |
592 Public method to replace a rule given the offset. |
623 Public method to replace a rule given the offset. |
593 |
624 |
594 @param rule reference to the rule to set |
625 @param rule reference to the rule to set |
595 @type AdBlockRule |
626 @type AdBlockRule |
596 @param offset offset of the rule to remove |
627 @param offset offset of the rule to remove |
597 @type int |
628 @type int |
598 @return requested rule |
629 @return requested rule |
599 @rtype AdBlockRule |
630 @rtype AdBlockRule |
600 """ |
631 """ |
601 if offset >= len(self.__rules): |
632 if offset >= len(self.__rules): |
602 return None |
633 return None |
603 |
634 |
604 self.__rules[offset] = rule |
635 self.__rules[offset] = rule |
605 self.rulesChanged.emit() |
636 self.rulesChanged.emit() |
606 |
637 |
607 return self.__rules[offset] |
638 return self.__rules[offset] |
608 |
639 |
609 def canEditRules(self): |
640 def canEditRules(self): |
610 """ |
641 """ |
611 Public method to check, if rules can be edited. |
642 Public method to check, if rules can be edited. |
612 |
643 |
613 @return flag indicating rules may be edited |
644 @return flag indicating rules may be edited |
614 @rtype bool |
645 @rtype bool |
615 """ |
646 """ |
616 return self.__custom |
647 return self.__custom |
617 |
648 |
618 def canBeRemoved(self): |
649 def canBeRemoved(self): |
619 """ |
650 """ |
620 Public method to check, if the subscription can be removed. |
651 Public method to check, if the subscription can be removed. |
621 |
652 |
622 @return flag indicating removal is allowed |
653 @return flag indicating removal is allowed |
623 @rtype bool |
654 @rtype bool |
624 """ |
655 """ |
625 return not self.__custom and not self.__defaultSubscription |
656 return not self.__custom and not self.__defaultSubscription |
626 |
657 |
627 def setRuleEnabled(self, offset, enabled): |
658 def setRuleEnabled(self, offset, enabled): |
628 """ |
659 """ |
629 Public method to enable a specific rule. |
660 Public method to enable a specific rule. |
630 |
661 |
631 @param offset offset of the rule |
662 @param offset offset of the rule |
632 @type int |
663 @type int |
633 @param enabled new enabled state |
664 @param enabled new enabled state |
634 @type bool |
665 @type bool |
635 @return reference to the changed rule |
666 @return reference to the changed rule |
636 @rtype AdBlockRule |
667 @rtype AdBlockRule |
637 """ |
668 """ |
638 if offset >= len(self.__rules): |
669 if offset >= len(self.__rules): |
639 return None |
670 return None |
640 |
671 |
641 rule = self.__rules[offset] |
672 rule = self.__rules[offset] |
642 rule.setEnabled(enabled) |
673 rule.setEnabled(enabled) |
643 self.rulesEnabledChanged.emit() |
674 self.rulesEnabledChanged.emit() |
644 |
675 |
645 if rule.isCSSRule(): |
676 if rule.isCSSRule(): |
646 from WebBrowser.WebBrowserWindow import WebBrowserWindow |
677 from WebBrowser.WebBrowserWindow import WebBrowserWindow |
|
678 |
647 WebBrowserWindow.mainWindow().reloadUserStyleSheet() |
679 WebBrowserWindow.mainWindow().reloadUserStyleSheet() |
648 |
680 |
649 return rule |
681 return rule |