use custom dict for db results, and fix fullscreen and downloads
This commit is contained in:
parent
fc91486a9b
commit
2da6599c44
|
@ -46,7 +46,6 @@ Linux (pyqt via pip):
|
|||
|
||||
## ToDo
|
||||
|
||||
* Use per-webview search bar instead of a global one
|
||||
* Create a new icon for the toot button
|
||||
* Create download manager
|
||||
* Handle cookies
|
||||
|
@ -56,6 +55,7 @@ Linux (pyqt via pip):
|
|||
* Ability to add new custom searches via local or remote json
|
||||
* Add optional auto-updater with stable/testing channels
|
||||
* Add ability to 'freeze' tabs
|
||||
* Add closed tab history
|
||||
* Rename the damn project
|
||||
|
||||
## Bugs
|
||||
|
|
|
@ -18,75 +18,65 @@ from ..config import var
|
|||
from ..functions import DotDict
|
||||
|
||||
|
||||
tables = {
|
||||
'config': OrderedDict([
|
||||
('id', 'INTEGER PRIMARY KEY'),
|
||||
('key', 'TEXT UNIQUE'),
|
||||
('value', 'TEXT')
|
||||
]),
|
||||
'bookmarks': OrderedDict([
|
||||
('id', 'INTEGER PRIMARY KEY'),
|
||||
('name', 'TEXT'),
|
||||
('url', 'TEXT UNIQUE'),
|
||||
('description', 'TEXT'),
|
||||
('category', 'TEXT'),
|
||||
('lastupdate', 'DATETIME')
|
||||
]),
|
||||
'links': OrderedDict([
|
||||
('id', 'INTEGER PRIMARY KEY'),
|
||||
('linkid', 'INTEGER')
|
||||
]),
|
||||
'mastodon': OrderedDict([
|
||||
('id', 'INTEGER PRIMARY KEY'),
|
||||
('username', 'TEXT'),
|
||||
('displayname', 'TEXT'),
|
||||
('domain', 'TEXT'),
|
||||
('fullname', 'TEXT UNIQUE'),
|
||||
('apikey', 'TEXT'),
|
||||
('tootlimit', 'INTEGER'),
|
||||
('avatar', 'TEXT'),
|
||||
('lastupdate', 'DATETIME')
|
||||
]),
|
||||
'siteoptions': OrderedDict([
|
||||
('id', 'INTEGER PRIMARY KEY'),
|
||||
('domain', 'TEXT UNIQUE'),
|
||||
('microphone', 'BOOLEAN DEFAULT 0'),
|
||||
('notification', 'BOOLEAN DEFAULT 0'),
|
||||
('camera', 'BOOLEAN DEFAULT 0'),
|
||||
('location', 'BOOLEAN DEFAULT 0'),
|
||||
('fullscreen', 'BOOLEAN DEFAULT 1'),
|
||||
('javascript', 'BOOLEAN DEFAULT 1'),
|
||||
('images', 'BOOLEAN DEFAULT 1'),
|
||||
('adblock', 'BOOLEAN DEFAULT 1'),
|
||||
('mastodon', 'BOOLEAN DEFAULT 0'),
|
||||
('allowhttp', 'BOOLEAN DEFAULT 1'),
|
||||
('capture', 'BOOLEAN DEFAULT 0'),
|
||||
('cookies', 'BOOLEAN DEFAULT 0'),
|
||||
('lastupdate', 'DATETIME')
|
||||
]),
|
||||
'tabs': OrderedDict([
|
||||
('id', 'INTEGER PRIMARY KEY'),
|
||||
('title', 'TEXT'),
|
||||
('url', 'TEXT'),
|
||||
('tabid', 'INTEGER')
|
||||
]),
|
||||
'search': OrderedDict([
|
||||
('id', 'INTEGER PRIMARY KEY'),
|
||||
('name', 'TEXT'),
|
||||
('keyword', 'TEXT UNIQUE'),
|
||||
('url', 'TEXT')
|
||||
]),
|
||||
#('cookies', {
|
||||
#'id': 'INTEGER PRIMARY KEY',
|
||||
#'name': 'TEXT NOT NULL',
|
||||
#'value': 'TEXT NOT NULL',
|
||||
#'domain': 'TEXT NOT NULL',
|
||||
#'path': 'TEXT NOT NULL',
|
||||
#'expires': 'INTEGER NOT NULL',
|
||||
#'http_only': 'BOOLEAN NOT NULL',
|
||||
#'secure': 'BOOLEAN NOT NULL'
|
||||
#})
|
||||
}
|
||||
tables = DotDict({
|
||||
'config': {
|
||||
'id': {'type': 'integer', 'options': ['primary key']},
|
||||
'key': {'type': 'text', 'options': ['unique']},
|
||||
'value': {'type': 'text'},
|
||||
},
|
||||
'bookmarks': {
|
||||
'id': {'type': 'integer', 'options': ['primary key']},
|
||||
'name': {'type': 'text'},
|
||||
'url': {'type': 'text', 'options': ['unique']},
|
||||
'description': {'type': 'text'},
|
||||
'category': {'type': 'text'},
|
||||
'lastupdate': {'type': 'datetime'},
|
||||
},
|
||||
'links': {
|
||||
'id': {'type': 'integer', 'options': ['primary key']},
|
||||
'linkid': {'type': 'integer'}
|
||||
},
|
||||
'mastodon': {
|
||||
'id': {'type': 'integer', 'options': ['primary key']},
|
||||
'username': {'type': 'text'},
|
||||
'displayname': {'type': 'text'},
|
||||
'domain': {'type': 'text'},
|
||||
'fullname': {'type': 'text', 'options': 'unique'},
|
||||
'apikey': {'type': 'text'},
|
||||
'tootlimit': {'type': 'integer'},
|
||||
'avatar': {'type': 'text'},
|
||||
'lastupdate': {'type': 'datetime'},
|
||||
},
|
||||
'siteoptions': {
|
||||
'id': {'type': 'integer', 'options': ['primary key']},
|
||||
'domain': {'type': 'text', 'options': 'unique'},
|
||||
'microphone': {'type': 'BOOLEAN', 'default': False},
|
||||
'notification': {'type': 'BOOLEAN', 'default': False},
|
||||
'camera': {'type': 'BOOLEAN', 'default': False},
|
||||
'location': {'type': 'BOOLEAN', 'default': False},
|
||||
'fullscreen': {'type': 'BOOLEAN', 'default': True},
|
||||
'javascript': {'type': 'BOOLEAN', 'default': True},
|
||||
'images': {'type': 'BOOLEAN', 'default': True},
|
||||
'adblock': {'type': 'BOOLEAN', 'default': True},
|
||||
'mastodon': {'type': 'BOOLEAN', 'default': False},
|
||||
'allowhttp': {'type': 'BOOLEAN', 'default': True},
|
||||
'capture': {'type': 'BOOLEAN', 'default': False},
|
||||
'cookies': {'type': 'BOOLEAN', 'default': False},
|
||||
'lastupdate': {'type': 'datetime'}
|
||||
},
|
||||
'tabs': {
|
||||
'id': {'type': 'integer', 'options': ['primary key']},
|
||||
'title': {'type': 'text'},
|
||||
'url': {'type': 'text'},
|
||||
'tabid': {'type': 'integer'}
|
||||
},
|
||||
'search': {
|
||||
'id': {'type': 'integer', 'options': ['primary key']},
|
||||
'name': {'type': 'text'},
|
||||
'keyword': {'type': 'text', 'options': ['unique']},
|
||||
'url': {'type': 'text'}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
SearchEngines = [
|
||||
|
@ -281,17 +271,24 @@ class DB():
|
|||
|
||||
|
||||
def CreateTable(self, table):
|
||||
layout = tables[table]
|
||||
layout = DotDict(tables.get(table))
|
||||
|
||||
if not layout:
|
||||
logging.error('Table config doesn\'t exist:', table)
|
||||
return
|
||||
|
||||
cmd = f'CREATE TABLE IF NOT EXISTS {table}('
|
||||
items = []
|
||||
|
||||
for k, v in layout.items():
|
||||
if k != 'foreignkey':
|
||||
items.append(f'{k} {v}')
|
||||
options = ' '.join(v.get('options', []))
|
||||
default = v.get('default')
|
||||
item = f'{k} {v.type.upper()} {options}'
|
||||
|
||||
else:
|
||||
field, ffield, fcol = layout[k]
|
||||
items.append(f'FOREIGN KEY({field}) REFERENCES {ffield}({fcol})')
|
||||
if default:
|
||||
item += f'DEFAULT {default}'
|
||||
|
||||
items.append(item)
|
||||
|
||||
cmd += ', '.join(items) + ')'
|
||||
|
||||
|
@ -356,7 +353,7 @@ class DB():
|
|||
return cookie
|
||||
|
||||
|
||||
class DBResult(dict):
|
||||
class DBResult(DotDict):
|
||||
def __init__(self, row, db, table, cursor):
|
||||
super().__init__()
|
||||
|
||||
|
@ -377,16 +374,24 @@ class DBResult(dict):
|
|||
|
||||
def __delattr__(self, name):
|
||||
if name not in ['db', 'table']:
|
||||
return self.__getitem__(name)
|
||||
return self.__delitem__(name)
|
||||
|
||||
else:
|
||||
return super().__delattr__(name)
|
||||
|
||||
|
||||
def __getattr__(self, value, default=None):
|
||||
val = super().__getattr__(value, default) if default else self[value]
|
||||
options = [value]
|
||||
|
||||
return DotDict(val) if type(val) == dict else val
|
||||
if default:
|
||||
options.append(default)
|
||||
|
||||
if value in self.keys():
|
||||
val = super().__getitem__(*options)
|
||||
return DotDict(val) if isinstance(val, dict) else val
|
||||
|
||||
else:
|
||||
return dict.__getattr__(*options)
|
||||
|
||||
|
||||
# Kept for backwards compatibility. Delete later.
|
||||
|
@ -413,25 +418,6 @@ def CreateDatabase():
|
|||
for engine in SearchEngines:
|
||||
db.insert('search', engine)
|
||||
|
||||
darktheme = {
|
||||
'name': 'Dark',
|
||||
'AlternateBase': '#353535',
|
||||
'Base': '#191919',
|
||||
'Button': '#353535',
|
||||
'ButtonText': '#ffffff',
|
||||
'BrightText': '#ff0000',
|
||||
'Highlight': '#2a82da',
|
||||
'HighlightedText': '#000000',
|
||||
'Link': '#2a82da',
|
||||
'Text': '#ffffff',
|
||||
'ToolTipBase': '#000000',
|
||||
'ToolTipText': '#ffffff',
|
||||
'Window': '#353535',
|
||||
'WindowText': '#ffffff'
|
||||
}
|
||||
|
||||
db.insert('themes', darktheme)
|
||||
|
||||
|
||||
perm = True
|
||||
backupdb = f'{var.database}.backup-{prev_dbversion}'
|
||||
|
|
|
@ -6,7 +6,7 @@ from ..Lib.IzzyLib.misc import boolean
|
|||
from ..Lib.IzzyLib import logging
|
||||
|
||||
from .connection import db, tables, ParseData
|
||||
from ..functions import psl
|
||||
from ..functions import psl, DotDict
|
||||
|
||||
from PyQt5.QtGui import QPalette, QColor
|
||||
|
||||
|
@ -50,18 +50,27 @@ def permissions(domain=None, defaults=False):
|
|||
else:
|
||||
rows = [db.cache['siteoptions'].fetch(domain)] if domain else cache.values()
|
||||
|
||||
for row in rows:
|
||||
if not row and defaults:
|
||||
values = [None, None, False, False, False, False, True, True, True, True, False, True, False, False, None]
|
||||
row = db.resclass['siteoptions'](*values)
|
||||
if rows == [None]:
|
||||
rows = None
|
||||
|
||||
for k, v in row.asdict().items():
|
||||
setattr(row, k, boolean(v) if k not in ['id', 'domain', 'lastupdate'] else v)
|
||||
if not rows and defaults:
|
||||
row = DotDict()
|
||||
|
||||
if domain:
|
||||
return row
|
||||
for k, v in tables.siteoptions.items():
|
||||
default = v.get('default')
|
||||
row[k] = default if default else None
|
||||
|
||||
data.append(row)
|
||||
return row
|
||||
|
||||
else:
|
||||
for row in rows:
|
||||
for k, v in row.items():
|
||||
row[k] = boolean(v) if k not in ['id', 'domain', 'lastupdate'] else v
|
||||
|
||||
if domain:
|
||||
return row
|
||||
|
||||
data.append(row)
|
||||
|
||||
return data
|
||||
|
||||
|
|
|
@ -349,7 +349,7 @@ class NewDownload(QDialog):
|
|||
logging.verbose('Starting download of', url)
|
||||
self.SetFilename()
|
||||
self.download.item.accept()
|
||||
self.download.item.finished.connect(lambda: profile._download_finished(self.download))
|
||||
self.download.item.finished.connect(lambda: self.profile._download_finished(self.download))
|
||||
|
||||
self.finished = True
|
||||
self.close()
|
||||
|
|
|
@ -455,22 +455,19 @@ def ParseSoundcloudInfo(data):
|
|||
|
||||
|
||||
class DotDict(dict):
|
||||
__setattr__ = dict.__setitem__
|
||||
__delattr__ = dict.__delitem__
|
||||
|
||||
def __init__(self, value=None, **kwargs):
|
||||
super().__init__()
|
||||
self.__setattr__ = dict.__setitem__
|
||||
self.__delattr__ = dict.__delitem__
|
||||
self.__getitem__ = self.__getattr__
|
||||
|
||||
if value.__class__ == str:
|
||||
self.FromJson(value)
|
||||
|
||||
elif value.__class__ in [dict, DotDict]:
|
||||
self.update(dict(value))
|
||||
self.update(value)
|
||||
|
||||
elif not value:
|
||||
pass
|
||||
|
||||
else:
|
||||
elif value:
|
||||
raise TypeError('The value must be a JSON string, dict, or another DotDict object, not', value.__class__)
|
||||
|
||||
if kwargs:
|
||||
|
@ -478,17 +475,8 @@ class DotDict(dict):
|
|||
self.update(kwargs)
|
||||
|
||||
|
||||
def __getattr__(self, value, default=None):
|
||||
val = self.get(value, default) if default else self[value]
|
||||
|
||||
return DotDict(val) if type(val) == dict else val
|
||||
|
||||
|
||||
def ToJson(self, **kwargs):
|
||||
if not kwargs.get('indent'):
|
||||
kwargs['indent'] = 4
|
||||
|
||||
return json.dumps(self, **kwargs)
|
||||
return self.__str__(**kwargs)
|
||||
|
||||
|
||||
def FromJson(self, string):
|
||||
|
@ -496,6 +484,29 @@ class DotDict(dict):
|
|||
self.update(data)
|
||||
|
||||
|
||||
def __parse_item(self, data):
|
||||
return DotDict(data) if type(data) == dict else data
|
||||
|
||||
|
||||
def items(self):
|
||||
data = []
|
||||
|
||||
for k, v in super(DotDict, self).items():
|
||||
value = self.__parse_item(v)
|
||||
data.append((k, value))
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def __str__(self, **kwargs):
|
||||
return json.dumps(self, **kwargs)
|
||||
|
||||
|
||||
def __getattr__(self, value, default=None):
|
||||
val = self.get(value, default) if default else self[value]
|
||||
return self.__parse_item(val)
|
||||
|
||||
|
||||
def ExceptionHandler(exctype, value, tb):
|
||||
sys._excepthook(exctype, value, tb)
|
||||
|
||||
|
|
|
@ -130,7 +130,7 @@ class WebEngineProfile(QWebEngineProfile):
|
|||
filename = Path(download.path())
|
||||
|
||||
else:
|
||||
filename = Path(download.downloadDirectory(), download.downloadFileName())
|
||||
filename = Path(download.item.downloadDirectory(), download.item.downloadFileName())
|
||||
|
||||
url = download.item.url().toString()
|
||||
|
||||
|
|
|
@ -187,15 +187,18 @@ class WebEngineView(QWebEngineView):
|
|||
logging.verbose(f'Rejected permission for {host}:', name)
|
||||
|
||||
|
||||
def _fullscreen_request(self, action, request):
|
||||
host = origin().host()
|
||||
def _fullscreen_request(self, request):
|
||||
host = request.origin().host()
|
||||
site = get.permissions(host, defaults=True)
|
||||
|
||||
if site.fullscreen:
|
||||
logging.verbose('Allowing fullscreen for:', host)
|
||||
logging.verbose('Allowing fullscreen for', host)
|
||||
request.accept()
|
||||
self.Fullscreen(request.toggleOn())
|
||||
|
||||
else:
|
||||
logging.verbose('Disallowing fullscreen for ', host)
|
||||
|
||||
|
||||
def _handle_auth(self, location, authenticator):
|
||||
url = location.toString()
|
||||
|
|
Reference in a new issue