Commit 9c5689b9 authored by Cédric Bellegarde's avatar Cédric Bellegarde

Add adblock support

parent da7f2974
......@@ -3,12 +3,17 @@ NULL =
bin_SCRIPTS = eolie
SUBDIRS = src data
SUBDIRS = src data python-webextension
EXTRA_DIST = \
eolie.in\
python-webextension/extension.py.in\
$(NULL)
webkitextensiondir = $(datadir)/eolie/webkitextension
webkitextension_DATA = python-webextension/pythonloader.so python-webextension/extension.py
CLEANFILES = \
$(bin_SCRIPTS)\
$(NULL)
......@@ -34,6 +39,13 @@ GITIGNOREFILES = \
m4 \
$(NULL)
python-webextension/extension.py: python-webextension/extension.py.in Makefile
$(AM_V_GEN)sed \
-e s!\@pythondir\@!$(pythondir)! \
-e s!\@pyexecdir\@!$(pyexecdir)! \
< $< > $@
chmod a+x $@
eolie: eolie.in Makefile
$(AM_V_GEN)sed \
-e s!\@srcdir\@!$(abs_top_srcdir)! \
......
......@@ -28,6 +28,8 @@ GOBJECT_INTROSPECTION_REQUIRE([1.35.9])
PKG_CHECK_MODULES([GTK], [gtk+-3.0 >= 3.14])
GLIB_COMPILE_RESOURCES=`$PKG_CONFIG --variable glib_compile_resources gio-2.0`
WEB_EXT_FLAGS=`$PKG_CONFIG pygobject-3.0 webkit2gtk-web-extension-4.0 python3 --cflags`
WEB_EXT_LIBS=`$PKG_CONFIG pygobject-3.0 webkit2gtk-web-extension-4.0 python3 --libs`
AC_SUBST(GLIB_COMPILE_RESOURCES)
AC_CONFIG_FILES([
......
......@@ -8,12 +8,13 @@
<property name="vexpand">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkButton" id="adblock-button">
<object class="GtkButton" id="adblock_button">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Hide ads</property>
<property name="valign">center</property>
<signal name="clicked" handler="_on_adblock_clicked" swapped="no"/>
<child>
<object class="GtkImage" id="adblock-button-image">
<property name="visible">True</property>
......
......@@ -54,3 +54,7 @@
background-color: transparent;
background-image: none;
}
.red {
color: shade(red, 0.8)
}
......@@ -16,10 +16,15 @@
<summary>Window maximized</summary>
<description>Window maximized state.</description>
</key>
<key type="i" name="paned-width">
<key type="i" name="paned-width">
<default>200</default>
<summary>INTERNAL</summary>
<description></description>
</key>
<key type="b" name="adblock">
<default>true</default>
<summary>Block ads on pages</summary>
<description></description>
</key>
</schema>
</schemalist>
......@@ -19,6 +19,8 @@ from gi.repository import Gio
localedir = '@localedir@'
pkgdatadir = '@pkgdatadir@'
sys.path.insert(1, '@pkgdatadir@/webextension')
from eolie.application import Application
def install_excepthook():
......@@ -44,7 +46,7 @@ if __name__ == "__main__":
resource = Gio.resource_load(os.path.join(pkgdatadir, 'eolie.gresource'))
Gio.Resource._register(resource)
app = Application()
app = Application(os.path.join(pkgdatadir, 'webkitextension'))
signal.signal(signal.SIGINT, signal.SIG_DFL)
if 'EOLIE_TRACE' in os.environ:
graphviz = GraphvizOutput()
......
python-webextension @ ec83c18d
Subproject commit ec83c18d1926de3fcce9794b1c048102bc2f73d2
......@@ -4,6 +4,7 @@ app_PYTHON = \
application.py\
art.py\
container.py\
database_adblock.py\
database_bookmarks.py\
database_history.py\
define.py\
......
......@@ -23,6 +23,8 @@ from eolie.window import Window
from eolie.art import Art
from eolie.database_history import DatabaseHistory
from eolie.database_bookmarks import DatabaseBookmarks
from eolie.database_adblock import DatabaseAdblock
from eolie.sqlcursor import SqlCursor
from eolie.search import Search
......@@ -38,9 +40,10 @@ class Application(Gtk.Application):
__COOKIES_PATH = "%s/cookies.db" % __LOCAL_PATH
__FAVICONS_PATH = "%s/favicons" % __LOCAL_PATH
def __init__(self):
def __init__(self, extension_dir):
"""
Create application
@param extension_dir as str
"""
Gtk.Application.__init__(
self,
......@@ -57,7 +60,7 @@ class Application(Gtk.Application):
if GLib.file_test(path, GLib.FileTest.EXISTS):
GLib.setenv('SSL_CERT_FILE', path, True)
break
self.__extension_dir = extension_dir
self.window = None
self.debug = False
self.cursors = {}
......@@ -88,7 +91,12 @@ class Application(Gtk.Application):
self.settings = Settings.new()
self.history = DatabaseHistory()
self.bookmarks = DatabaseBookmarks()
# We store cursors for main thread
SqlCursor.add(self.history)
SqlCursor.add(self.bookmarks)
self.bookmarks.import_firefox()
adblock = DatabaseAdblock()
adblock.update()
self.art = Art()
self.search = Search()
......@@ -102,6 +110,9 @@ class Application(Gtk.Application):
# Set some WebKit defaults
context = WebKit2.WebContext.get_default()
GLib.setenv('PYTHONPATH', self.__extension_dir, True)
context.set_web_extensions_directory(self.__extension_dir)
data_manager = WebKit2.WebsiteDataManager()
context.new_with_website_data_manager(data_manager)
context.set_process_model(
......
# Copyright (c) 2014-2016 Cedric Bellegarde <cedric.bellegarde@adishatz.org>
# Copyright (c) 2013 Vadim Rutkovsky <vrutkovs@redhat.com>
# Copyright (c) 2013 Arnel A. Borja <kyoushuu@yahoo.com>
# Copyright (c) 2013 Seif Lotfy <seif@lotfy.com>
# Copyright (c) 2013 Guillaume Quintard <guillaume.quintard@gmail.com>
# Copyright (c) 2013 Lubosz Sarnecki <lubosz@gmail.com>
# Copyright (c) 2013 Sai Suman Prayaga <suman.sai14@gmail.com>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
......
# Copyright (c) 2014-2016 Cedric Bellegarde <cedric.bellegarde@adishatz.org>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from gi.repository import Soup, Gio, GLib
from urllib.parse import urlparse
import sqlite3
from time import time, sleep
from threading import Thread
from eolie.sqlcursor import SqlCursor
class DatabaseAdblock:
"""
Eolie adblock db
"""
if GLib.getenv("XDG_DATA_HOME") is None:
__LOCAL_PATH = GLib.get_home_dir() + "/.local/share/eolie"
else:
__LOCAL_PATH = GLib.getenv("XDG_DATA_HOME") + "/eolie"
DB_PATH = "%s/adblock.db" % __LOCAL_PATH
__URIS = ["https://adaway.org/hosts.txt",
"http://winhelp2002.mvps.org/hosts.txt",
"http://hosts-file.net/ad_servers.txt",
"https://pgl.yoyo.org/adservers/serverlist.php?"
"hostformat=hosts&showintro=0&mimetype=plaintext"]
# SQLite documentation:
# In SQLite, a column with type INTEGER PRIMARY KEY
# is an alias for the ROWID.
# Here, we define an id INT PRIMARY KEY but never feed it,
# this make VACUUM not destroy rowids...
__create_adblock = '''CREATE TABLE adblock (
id INTEGER PRIMARY KEY,
dns TEXT NOT NULL,
mtime INT NOT NULL
)'''
def __init__(self):
"""
Create database tables or manage update if needed
"""
self.__cancellable = Gio.Cancellable.new()
f = Gio.File.new_for_path(self.DB_PATH)
# Lazy loading if not empty
self.__sleep = 0.5
if not f.query_exists():
try:
self.__sleep = 0.1
d = Gio.File.new_for_path(self.__LOCAL_PATH)
if not d.query_exists():
d.make_directory_with_parents()
# Create db schema
with SqlCursor(self) as sql:
sql.execute(self.__create_adblock)
sql.commit()
except Exception as e:
print("DatabaseAdblock::__init__(): %s" % e)
def update(self):
"""
Update database
"""
if Gio.NetworkMonitor.get_default().get_network_available():
self.__mtime = int(time())
self.__thread = Thread(target=self.__update)
self.__thread.daemon = True
self.__thread.start()
def stop(self):
"""
Stop update
"""
self.__cancellable.cancel()
self.__cancellable.reset()
def is_blocked(self, uri):
"""
Return True if uri is blocked
@param uri as str
@return bool
"""
try:
parse = urlparse(uri)
with SqlCursor(self) as sql:
result = sql.execute("SELECT mtime FROM adblock\
WHERE dns=?", (parse.netloc,))
v = result.fetchone()
return v is not None
except Exception as e:
print("DatabaseAdblock::is_blocked():", e)
return False
def get_cursor(self):
"""
Return a new sqlite cursor
"""
try:
c = sqlite3.connect(self.DB_PATH, 600.0)
return c
except:
exit(-1)
#######################
# PRIVATE #
#######################
def __update(self):
"""
Update database
"""
result = ""
try:
for uri in self.__URIS:
session = Soup.Session.new()
request = session.request(uri)
stream = request.send(self.__cancellable)
bytes = bytearray(0)
buf = stream.read_bytes(1024, self.__cancellable).get_data()
while buf:
bytes += buf
buf = stream.read_bytes(
1024, self.__cancellable).get_data()
result = bytes.decode('utf-8')
for line in result.split('\n'):
if self.__cancellable.is_cancelled():
raise IOError("Cancelled")
sleep(self.__sleep)
if line.startswith('#'):
continue
array = line.replace(
' ', '\t', 1).replace('\t', '@', 1).split('@')
if len(array) <= 1:
continue
dns = array[1].replace(
' ', '').replace('\r', '').split('#')[0]
# Update entry if exists, create else
with SqlCursor(self) as sql:
result = sql.execute("SELECT mtime FROM adblock\
WHERE dns=?", (dns,))
v = result.fetchone()
if v is not None:
sql.execute("UPDATE adblock set mtime=?\
WHERE dns=?", (self.__mtime, dns))
else:
sql.execute("INSERT INTO adblock\
(dns, mtime)\
VALUES (?, ?)",
(dns, self.__mtime))
sql.commit()
# Delete removed entries
with SqlCursor(self) as sql:
sql.execute("DELETE FROM adblock\
WHERE mtime!=?", (self.__mtime,))
except Exception as e:
print("DatabaseAdlbock:__update():", e)
......@@ -10,7 +10,9 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from gi.repository import Gtk
from gi.repository import Gtk, GLib
from eolie.define import El
class ToolbarEnd(Gtk.Bin):
......@@ -25,12 +27,28 @@ class ToolbarEnd(Gtk.Bin):
Gtk.Bin.__init__(self)
builder = Gtk.Builder()
builder.add_from_resource('/org/gnome/Eolie/ToolbarEnd.ui')
# builder.connect_signals(self)
builder.connect_signals(self)
if El().settings.get_value('adblock'):
builder.get_object(
'adblock_button').get_style_context().add_class('red')
self.add(builder.get_object('end'))
#######################
# PROTECTED #
#######################
def _on_adblock_clicked(self, button):
"""
Switch add blocking on/off
@param button as Gtk.Button
"""
value = not El().settings.get_value('adblock')
El().settings.set_value('adblock',
GLib.Variant('b', value))
if value:
button.get_style_context().add_class('red')
else:
button.get_style_context().remove_class('red')
#######################
# PRIVATE #
#######################
......@@ -12,6 +12,8 @@
import unicodedata
from eolie.define import El
def noaccents(string):
"""
......@@ -21,3 +23,12 @@ def noaccents(string):
"""
nfkd_form = unicodedata.normalize('NFKD', string)
return u"".join([c for c in nfkd_form if not unicodedata.combining(c)])
def debug(str):
"""
Print debug
@param debug as str
"""
if El().debug is True:
print(str)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment