initial commit
This commit is contained in:
4
gotify_tray/database/__init__.py
Normal file
4
gotify_tray/database/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from .cache import Cache
|
||||
from .database import Database
|
||||
from .downloader import Downloader
|
||||
from .settings import Settings
|
||||
74
gotify_tray/database/cache.py
Normal file
74
gotify_tray/database/cache.py
Normal file
@@ -0,0 +1,74 @@
|
||||
import glob
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
|
||||
import requests
|
||||
|
||||
from PyQt6 import QtCore
|
||||
|
||||
from .database import Database
|
||||
|
||||
logger = logging.getLogger("logger")
|
||||
|
||||
|
||||
class Cache(object):
|
||||
def __init__(self):
|
||||
self.database = Database("cache")
|
||||
self.cursor = self.database.cursor()
|
||||
self.cursor.execute(
|
||||
"""CREATE TABLE IF NOT EXISTS cache (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
url TEXT,
|
||||
filename TEXT,
|
||||
cached_on TEXT)
|
||||
"""
|
||||
)
|
||||
|
||||
# create a directory to store cached files
|
||||
path = QtCore.QStandardPaths.standardLocations(
|
||||
QtCore.QStandardPaths.StandardLocation.CacheLocation
|
||||
)[0]
|
||||
self.cache_dir = os.path.join(path, "cache")
|
||||
os.makedirs(self.cache_dir, exist_ok=True)
|
||||
|
||||
def clear(self):
|
||||
self.cursor.execute("DELETE FROM cache")
|
||||
self.database.commit()
|
||||
for filename in glob.glob(self.cache_dir + "/*"):
|
||||
os.remove(filename)
|
||||
|
||||
def lookup(self, key: str) -> str:
|
||||
q = self.cursor.execute(
|
||||
"SELECT filename, cached_on FROM cache WHERE url=?", (key,)
|
||||
).fetchone()
|
||||
if q:
|
||||
# Cache hit
|
||||
filename, cached_on = q
|
||||
return filename
|
||||
else:
|
||||
# Cache miss
|
||||
return ""
|
||||
|
||||
def store(
|
||||
self, key: str, response: requests.Response, add_time: bool = True
|
||||
) -> str:
|
||||
# Create a file and store the response contents
|
||||
filename = str(time.time()).replace(".", "") if add_time else ""
|
||||
if "Content-Disposition" in response.headers.keys():
|
||||
filename += response.headers["Content-Disposition"]
|
||||
else:
|
||||
filename += response.url.split("/")[-1]
|
||||
|
||||
filename = "".join([c for c in filename if c.isalpha() or c.isdigit()]).rstrip()
|
||||
filename = os.path.join(self.cache_dir, filename)
|
||||
|
||||
with open(filename, "wb") as f:
|
||||
f.write(response.content)
|
||||
|
||||
self.cursor.execute(
|
||||
"INSERT INTO cache (url, filename, cached_on) VALUES(?, ?, datetime('now', 'localtime'))",
|
||||
(key, filename),
|
||||
)
|
||||
self.database.commit()
|
||||
return filename
|
||||
19
gotify_tray/database/database.py
Normal file
19
gotify_tray/database/database.py
Normal file
@@ -0,0 +1,19 @@
|
||||
import logging
|
||||
import os
|
||||
import sqlite3
|
||||
|
||||
from PyQt6 import QtCore
|
||||
|
||||
|
||||
logger = logging.getLogger("logger")
|
||||
|
||||
|
||||
class Database(sqlite3.Connection):
|
||||
def __init__(self, database: str, *args, **kwargs):
|
||||
self.dir = QtCore.QStandardPaths.standardLocations(
|
||||
QtCore.QStandardPaths.StandardLocation.CacheLocation
|
||||
)[0]
|
||||
os.makedirs(self.dir, exist_ok=True)
|
||||
path = os.path.join(self.dir, database + ".db.sqlite3")
|
||||
super(Database, self).__init__(database=path, *args, **kwargs)
|
||||
self.row_factory = sqlite3.Row
|
||||
18
gotify_tray/database/default_settings.py
Normal file
18
gotify_tray/database/default_settings.py
Normal file
@@ -0,0 +1,18 @@
|
||||
DEFAULT_SETTINGS = {
|
||||
"MainWindow/start_minimized": True,
|
||||
"MainWindow/theme": "default",
|
||||
"MainWidget/status_image/size": 28,
|
||||
"MessageWidget/image/show": True,
|
||||
"MessageWidget/image/size": 33,
|
||||
"MessageWidget/font/title": "Noto Sans,17,-1,5,75,0,0,0,0,0,Bold",
|
||||
"MessageWidget/font/date": "Noto Sans,11,-1,5,50,1,0,0,0,0,Italic",
|
||||
"MessageWidget/font/content": "Noto Sans,11,-1,5,50,0,0,0,0,0,Regular",
|
||||
"ApplicationModelItem/icon/show": True,
|
||||
"ApplicationModelItem/icon/size": 33,
|
||||
"tray/notifications/enabled": True,
|
||||
"tray/notifications/priority": 5,
|
||||
"tray/show": True,
|
||||
"tray/minimize": True,
|
||||
"tray/notifications/duration_ms": 5000,
|
||||
"tray/notifications/icon/show": True,
|
||||
}
|
||||
78
gotify_tray/database/downloader.py
Normal file
78
gotify_tray/database/downloader.py
Normal file
@@ -0,0 +1,78 @@
|
||||
import logging
|
||||
|
||||
import requests
|
||||
|
||||
from .cache import Cache
|
||||
from .settings import Settings
|
||||
|
||||
|
||||
logger = logging.getLogger("logger")
|
||||
settings = Settings("gotify-tray")
|
||||
|
||||
|
||||
class Downloader(object):
|
||||
def __init__(self):
|
||||
self.cache = Cache()
|
||||
self.session = requests.Session()
|
||||
self.session.proxies.update(
|
||||
{
|
||||
"https": settings.value("proxies/https", type=str),
|
||||
"http": settings.value("proxies/http", type=str),
|
||||
}
|
||||
)
|
||||
|
||||
def get(self, url: str) -> requests.Response:
|
||||
"""
|
||||
Get the response of an http get request.
|
||||
Bypasses the cache.
|
||||
"""
|
||||
return self.session.get(url)
|
||||
|
||||
def get_bytes(self, url: str, cached: bool = True, add_time: bool = True) -> bytes:
|
||||
"""
|
||||
Get the content of an http get request, as bytes.
|
||||
Optionally use the cache.
|
||||
"""
|
||||
if cached:
|
||||
# Retrieve from cache
|
||||
filename = self.cache.lookup(url)
|
||||
if filename:
|
||||
with open(filename, "rb") as f:
|
||||
return f.read()
|
||||
|
||||
try:
|
||||
response = self.get(url)
|
||||
except Exception as e:
|
||||
logger.error(f"get_bytes: downloading {url} failed.: {e}")
|
||||
return b""
|
||||
|
||||
if not response.ok:
|
||||
return b""
|
||||
|
||||
if cached:
|
||||
# Store in cache
|
||||
self.cache.store(url, response, add_time=add_time)
|
||||
|
||||
return response.content
|
||||
|
||||
def get_filename(
|
||||
self, url: str, retrieve_from_cache: bool = True, add_time: bool = True
|
||||
) -> str:
|
||||
"""
|
||||
Get the content of an http get request, as a filename.
|
||||
"""
|
||||
if retrieve_from_cache:
|
||||
filename = self.cache.lookup(url)
|
||||
if filename:
|
||||
return filename
|
||||
|
||||
try:
|
||||
response = self.get(url)
|
||||
except Exception as e:
|
||||
logger.error(f"get_filename: downloading {url} failed.: {e}")
|
||||
return ""
|
||||
|
||||
if not response.ok:
|
||||
return ""
|
||||
|
||||
return self.cache.store(url, response, add_time=add_time)
|
||||
13
gotify_tray/database/settings.py
Normal file
13
gotify_tray/database/settings.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from typing import Any
|
||||
from .default_settings import DEFAULT_SETTINGS
|
||||
|
||||
|
||||
from PyQt6 import QtCore
|
||||
|
||||
|
||||
class Settings(QtCore.QSettings):
|
||||
def value(self, key: str, defaultValue: Any = None, type: Any = None) -> Any:
|
||||
if type:
|
||||
return super().value(key, defaultValue=defaultValue or DEFAULT_SETTINGS.get(key), type=type)
|
||||
else:
|
||||
return super().value(key, defaultValue=defaultValue or DEFAULT_SETTINGS.get(key))
|
||||
Reference in New Issue
Block a user