From 980cb7b851616fda516daa54f2037cdbfa93566d Mon Sep 17 00:00:00 2001 From: mocha Date: Thu, 23 May 2024 00:12:39 +0200 Subject: [PATCH 1/7] barebones working prototype for HTTP image embedding --- convo.py | 29 +++++++++++++++++ embeds.py | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++ parsetools.py | 29 +++++++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 embeds.py diff --git a/convo.py b/convo.py index ca3fe4ed..c4ce423f 100644 --- a/convo.py +++ b/convo.py @@ -14,6 +14,7 @@ from dataobjs import PesterHistory from parsetools import convertTags, lexMessage, mecmd, colorBegin, colorEnd, smiledict import parsetools +import embeds PchumLog = logging.getLogger("pchumLogger") @@ -394,6 +395,11 @@ def __init__(self, theme, parent=None): QtCore.QUrl("smilies/%s" % (smiledict[k])), "smilies/%s" % (smiledict[k]), ) + + embeds.manager.embed_loading.connect(self.registerEmbed) + embeds.manager.embed_loaded.connect(self.showEmbed) + for embed in embeds.manager.get_embeds(): + self.showEmbed(embed) # self.mainwindow.animationSetting[bool].connect(self.animateChanged) def addAnimation(self, url, fileName): @@ -409,6 +415,29 @@ def addAnimation(self, url, fileName): self.urls[movie] = url movie.frameChanged.connect(movie.animate) # (int frameNumber) + def setResource(self, uri, pixmap): + try: + # PyQt6 + resource_type = QtGui.QTextDocument.ResourceType.ImageResource.value + except AttributeError: + # PyQt5 + resource_type = QtGui.QTextDocument.ResourceType.ImageResource + self.document().addResource( + resource_type, + QtCore.QUrl(uri), + pixmap, + ) + self.setLineWrapColumnOrWidth(self.lineWrapColumnOrWidth()) + + def registerEmbed(self, url): + if embeds.manager.has_embed(url): + self.showEmbed(url) + else: + self.setResource(url, QtGui.QPixmap("smilies/whatpumpkin.png")) + + def showEmbed(self, url): + self.setResource(url, embeds.manager.get_embed(url)) + """ @QtCore.pyqtSlot(bool) def animateChanged(self, animate): diff --git a/embeds.py b/embeds.py new file mode 100644 index 00000000..b53fbf33 --- /dev/null +++ b/embeds.py @@ -0,0 +1,89 @@ +from collections import OrderedDict +import logging + +try: + from PyQt6 import QtCore, QtGui, QtWidgets, QtNetwork +except ImportError: + print("PyQt5 fallback (thememanager.py)") + from PyQt5 import QtCore, QtGui, QtWidgets, QtNetwork + +from theme_repo_manager import get_request + + +PchumLog = logging.getLogger("pchumLogger") + + +class EmbedsManager(QtCore.QObject): + cache = OrderedDict() + downloading = set() + max_items = 100 + + embed_loading = QtCore.pyqtSignal(str) # when the get request starts (url: str) + embed_loaded = QtCore.pyqtSignal( + str + ) # when the embed is done downloading (url: str) + embed_purged = QtCore.pyqtSignal( + str + ) # when the embed is cleared from memory (url: str) + embed_failed = QtCore.pyqtSignal( + str, str + ) # when the embed fails to load (url: str, reason: str) + + def __init__(self): + super().__init__() + + def get_embeds(self): + return list(self.cache.keys()) + + def get_embed(self, url, placeholder=None): + ## Returns the QPixmap object of the embed image after fetching + ## Should be called when the embed_loaded signal has been emitted, OR after checking that has_embed == True + return self.cache.get(url, placeholder) + + def has_embed(self, url): + return url in self.cache + + def fetch_embed(self, url, ignore_cache=False): + ## Downloads a new embed if it does not exist yet + if not ignore_cache and self.has_embed(url): + self.cache.move_to_end(url) + PchumLog.debug( + f"Requested embed fetch of {url}, but it was already fetched" + ) + return + elif url in self.downloading: + PchumLog.debug( + f"Requested embed fetch of {url} but its already in progress" + ) + return + + PchumLog.info(f"Fetching embed of {url}") + + self.downloading.add( + url + ) # Track which embeds are downloading so we dont do double-fetches + self.embed_loading.emit(url) + reply = get_request(url) + reply.finished.connect(lambda: self._on_request_finished(reply, url)) + + def _on_request_finished(self, reply, url): + ## Callback, called when an embed is finished downloading + self.downloading.remove(url) + if reply.error() == QtNetwork.QNetworkReply.NetworkError.NoError: + PchumLog.info(f"Finished fetching embed {url}") + + pixmap = QtGui.QPixmap() + pixmap.loadFromData(reply.readAll()) + + self.cache[url] = pixmap + self.embed_loaded.emit(url) + + if len(self.cache) > self.max_items: + to_purge = list(self.cache.keys())[0] + self.embed_purged.emit(to_purge) + del self.cache[to_purge] + else: + PchumLog.error("Error fetching embed %s: %s" % (url, reply.error())) + + +manager = EmbedsManager() diff --git a/parsetools.py b/parsetools.py index b9a2bb35..9665149c 100644 --- a/parsetools.py +++ b/parsetools.py @@ -19,6 +19,8 @@ from pyquirks import PythonQuirks from scripts.services import BOTNAMES +import embeds + PchumLog = logging.getLogger("pchumLogger") # I'll clean up the things that are no longer needed once the transition is @@ -42,6 +44,12 @@ _alternian_begin = re.compile(r"") # Matches get set to alternian font _alternian_end = re.compile(r"") + +_embedre = re.compile( + r"(?i)(?:^|(?<=\s))(?:(?:https?):\/\/)[^\s]+(?:\.png|\.jpg|\.jpeg)(?:\?[^\s]+)?" +) + + quirkloader = ScriptQuirks() _functionre = None @@ -163,6 +171,21 @@ def convert(self, format): return self.string +class embedlink(lexercon.Chunk): + def __init__(self, url): + self.url = url + print("GO FETCH ", url) + embeds.manager.fetch_embed(url) + + def convert(self, format): + if format == "html": + return "%s%s" % (self.url, self.url, self.url, self.url) + elif format == "bbcode": + return f"[url]{self.url}[/url]" + else: + return self.url + + class hyperlink(lexercon.Chunk): def __init__(self, string): self.string = string @@ -212,8 +235,12 @@ class imagelink(lexercon.Chunk): def __init__(self, string, img): self.string = string self.img = img + print("Imagelinmk: ", string, img) + # raise Exception(f'{string} {img}') def convert(self, format): + # raise Exception(format) + print("TIME FOR ", format) if format == "html": return self.string elif format == "bbcode": @@ -258,6 +285,7 @@ def __init__(self, string): self.string = string def convert(self, format): + print("SMILEY:: ", format) if format == "html": return "{}".format( smiledict[self.string], @@ -318,6 +346,7 @@ def lexMessage(string: str): # actually use it, save for Chumdroid...which shouldn't. # When I change out parsers, I might add it back in. ##(formatBegin, _format_begin), (formatEnd, _format_end), + (embedlink, _embedre), (imagelink, _imgre), (hyperlink, _urlre), (memolex, _memore), From 969f2a581662b6eff224b15485d3b5d1ac4beb3c Mon Sep 17 00:00:00 2001 From: mocha Date: Thu, 23 May 2024 02:13:06 +0200 Subject: [PATCH 2/7] improved layout & size --- convo.py | 7 ++++++- embeds.py | 39 +++++++++++++++++++++++++++------------ img/embed_failed.png | Bin 0 -> 371 bytes img/loading_embed.png | Bin 0 -> 444 bytes parsetools.py | 5 ++++- 5 files changed, 37 insertions(+), 14 deletions(-) create mode 100644 img/embed_failed.png create mode 100644 img/loading_embed.png diff --git a/convo.py b/convo.py index c4ce423f..6fa9bf3f 100644 --- a/convo.py +++ b/convo.py @@ -398,6 +398,11 @@ def __init__(self, theme, parent=None): embeds.manager.embed_loading.connect(self.registerEmbed) embeds.manager.embed_loaded.connect(self.showEmbed) + embeds.manager.embed_failed.connect( + lambda url, error: self.setResource( + url, QtGui.QPixmap("img/embed_failed.png") + ) + ) for embed in embeds.manager.get_embeds(): self.showEmbed(embed) # self.mainwindow.animationSetting[bool].connect(self.animateChanged) @@ -433,7 +438,7 @@ def registerEmbed(self, url): if embeds.manager.has_embed(url): self.showEmbed(url) else: - self.setResource(url, QtGui.QPixmap("smilies/whatpumpkin.png")) + self.setResource(url, QtGui.QPixmap("img/loading_embed.png")) def showEmbed(self, url): self.setResource(url, embeds.manager.get_embed(url)) diff --git a/embeds.py b/embeds.py index b53fbf33..b534d459 100644 --- a/embeds.py +++ b/embeds.py @@ -12,11 +12,20 @@ PchumLog = logging.getLogger("pchumLogger") +## embeds.py +# system for fetching & displaying image previews for image URLs +# has a single instance called `manager` at the bottom of this file + +## TODO: +## - add domain filters in settings +## - add "ignore filters" or whatever toggle in settings +## - *verify* domain filters + class EmbedsManager(QtCore.QObject): cache = OrderedDict() downloading = set() - max_items = 100 + max_items = 50 embed_loading = QtCore.pyqtSignal(str) # when the get request starts (url: str) embed_loaded = QtCore.pyqtSignal( @@ -33,41 +42,45 @@ def __init__(self): super().__init__() def get_embeds(self): + """Returns all cached embeds""" return list(self.cache.keys()) def get_embed(self, url, placeholder=None): - ## Returns the QPixmap object of the embed image after fetching - ## Should be called when the embed_loaded signal has been emitted, OR after checking that has_embed == True + """Returns the QPixmap object of the embed image after fetching + Should be called when the embed_loaded signal has been emitted, OR after checking that has_embed == True + """ + if url in self.cache: + self.cache.move_to_end(url) + # make sure that embeds that were fetched a while ago but recently used do not get purged first return self.cache.get(url, placeholder) def has_embed(self, url): return url in self.cache def fetch_embed(self, url, ignore_cache=False): - ## Downloads a new embed if it does not exist yet + """Downloads a new embed if it does not exist yet""" if not ignore_cache and self.has_embed(url): - self.cache.move_to_end(url) PchumLog.debug( - f"Requested embed fetch of {url}, but it was already fetched" + "Requested embed fetch of %s, but it was already fetched" % (url,) ) return elif url in self.downloading: PchumLog.debug( - f"Requested embed fetch of {url} but its already in progress" + "Requested embed fetch of %s, but it is already being fetched" % (url,) ) return - PchumLog.info(f"Fetching embed of {url}") + PchumLog.info("Fetching embed of %s" % (url,)) + + self.downloading.add(url) + # Track which embeds are downloading so we dont do double-fetches - self.downloading.add( - url - ) # Track which embeds are downloading so we dont do double-fetches self.embed_loading.emit(url) reply = get_request(url) reply.finished.connect(lambda: self._on_request_finished(reply, url)) def _on_request_finished(self, reply, url): - ## Callback, called when an embed is finished downloading + """Callback, called when an embed has finished downloading""" self.downloading.remove(url) if reply.error() == QtNetwork.QNetworkReply.NetworkError.NoError: PchumLog.info(f"Finished fetching embed {url}") @@ -80,10 +93,12 @@ def _on_request_finished(self, reply, url): if len(self.cache) > self.max_items: to_purge = list(self.cache.keys())[0] + PchumLog.debug("Purging embed %s" % (to_purge,)) self.embed_purged.emit(to_purge) del self.cache[to_purge] else: PchumLog.error("Error fetching embed %s: %s" % (url, reply.error())) + self.embed_failed.emit(url, str(reply.error())) manager = EmbedsManager() diff --git a/img/embed_failed.png b/img/embed_failed.png new file mode 100644 index 0000000000000000000000000000000000000000..be33e587a71b31ca3d9e7a0db6c2e25501bb600f GIT binary patch literal 371 zcmeAS@N?(olHy`uVBq!ia0vp^Wk4*%!3-pK%G}BaQjEnx?oJHr&dIz4a`*#$LR^9L z|NsBNB*WcRg5rmAo&Y(lB|(0{Ac_An7u0|zF*16(IEHw1-kt0%bVPx}g|Ya*v46+` zwF&2Q(pDWh)^VWun!w&0vu@R|*dFt)?A_xpvWpil-r96JMrBin%9`Ih>Tmu0H+NC{ zVXtjrh3=e|D&G!OMjijQsKeIH*vfx{jkPeF^0qQbv9-yP1^4`YjEXaU^xfLlDWlzE z-CX)Yb3$H-|NY%|6$@%t91ecJu}9ZPEoyHu z@p)B|KCns`uM%kixW%dN7}xP-Z-_EA@mjd+~SQXvcS+` N@O1TaS?83{1OVSdpf&&i literal 0 HcmV?d00001 diff --git a/img/loading_embed.png b/img/loading_embed.png new file mode 100644 index 0000000000000000000000000000000000000000..d06a89c6addd0bce85424cab75c00df6b6b4f35c GIT binary patch literal 444 zcmV;t0YmPx$c1c7*R9J=WSkV%MAP9`6|Nmw0$%f-#fwauJo#~+y*j2>CmgSE}f<};*Qi^9o zL_@S?pv|L2ch7j66|f~}1Uz)5ufGNIej8}>xI?^^2jtJ$m??P(z30&@-o^u>ib2OG z5s_E*k>i(}c=m`>^iu%yr3eso6RS_@?51$li;| z;=1#Q#IrOW)tTTtbbPM9$v1f^Wq&kL)|lnb{Uk&M|HMTxtwPXztb|EUG;d7@(ixdU z3&M%zuy#>YRAd)scdBNeiP5XCXyNSHtZu$Z924A7c8t(^B_~X5=8s)AUUyIOh^}1Y zjI7gytZ2ZcrZTjV1o&q6RAZ20000%s%s" % (self.url, self.url, self.url, self.url) + return ( + "%s
%s" + % (self.url, self.url, self.url, self.url, self.url) + ) elif format == "bbcode": return f"[url]{self.url}[/url]" else: From 832df7b81007f8fc9125972bc7b775a6677c2dae Mon Sep 17 00:00:00 2001 From: mocha Date: Sun, 22 Sep 2024 01:12:10 +0200 Subject: [PATCH 3/7] implement UI, almost done i think --- convo.py | 10 ++++---- embeds.py | 29 +++++++++++++++++++---- menus.py | 63 +++++++++++++++++++++++++++++++++++++++++++++++++ parsetools.py | 18 +++++++++----- pesterchum.py | 12 ++++++++++ user_profile.py | 24 +++++++++++++++++++ 6 files changed, 140 insertions(+), 16 deletions(-) diff --git a/convo.py b/convo.py index 6fa9bf3f..4fd925a0 100644 --- a/convo.py +++ b/convo.py @@ -398,11 +398,7 @@ def __init__(self, theme, parent=None): embeds.manager.embed_loading.connect(self.registerEmbed) embeds.manager.embed_loaded.connect(self.showEmbed) - embeds.manager.embed_failed.connect( - lambda url, error: self.setResource( - url, QtGui.QPixmap("img/embed_failed.png") - ) - ) + embeds.manager.embed_failed.connect(self.showEmbedError) for embed in embeds.manager.get_embeds(): self.showEmbed(embed) # self.mainwindow.animationSetting[bool].connect(self.animateChanged) @@ -443,6 +439,10 @@ def registerEmbed(self, url): def showEmbed(self, url): self.setResource(url, embeds.manager.get_embed(url)) + def showEmbedError(self, url, error=None): + # Sets the resource to generic "wuh oh failed" image + self.setResource(url, QtGui.QPixmap("img/embed_failed.png")) + """ @QtCore.pyqtSlot(bool) def animateChanged(self, animate): diff --git a/embeds.py b/embeds.py index b534d459..a9bf37e3 100644 --- a/embeds.py +++ b/embeds.py @@ -27,6 +27,8 @@ class EmbedsManager(QtCore.QObject): downloading = set() max_items = 50 + main_window = None + embed_loading = QtCore.pyqtSignal(str) # when the get request starts (url: str) embed_loaded = QtCore.pyqtSignal( str @@ -57,20 +59,37 @@ def get_embed(self, url, placeholder=None): def has_embed(self, url): return url in self.cache + def check_trustlist(self, url): + for item in self.main_window.config.userprofile.getTrustedDomains(): + print("~~", item) + if url.startswith(item): + print("yurt") + return True + print("nah") + return False + def fetch_embed(self, url, ignore_cache=False): """Downloads a new embed if it does not exist yet""" + + if not self.check_trustlist(url): + PchumLog.warning( + "Requested embed fetch of %s denied because it does not match te trust filter.", + url, + ) + return + if not ignore_cache and self.has_embed(url): PchumLog.debug( - "Requested embed fetch of %s, but it was already fetched" % (url,) + "Requested embed fetch of %s, but it was already fetched", url ) return elif url in self.downloading: PchumLog.debug( - "Requested embed fetch of %s, but it is already being fetched" % (url,) + "Requested embed fetch of %s, but it is already being fetched", url ) return - PchumLog.info("Fetching embed of %s" % (url,)) + PchumLog.info("Fetching embed of %s", url) self.downloading.add(url) # Track which embeds are downloading so we dont do double-fetches @@ -93,11 +112,11 @@ def _on_request_finished(self, reply, url): if len(self.cache) > self.max_items: to_purge = list(self.cache.keys())[0] - PchumLog.debug("Purging embed %s" % (to_purge,)) + PchumLog.debug("Purging embed %s", to_purge) self.embed_purged.emit(to_purge) del self.cache[to_purge] else: - PchumLog.error("Error fetching embed %s: %s" % (url, reply.error())) + PchumLog.error("Error fetching embed %s: %s", url, reply.error()) self.embed_failed.emit(url, str(reply.error())) diff --git a/menus.py b/menus.py index 72fd6440..d4b8d5f8 100644 --- a/menus.py +++ b/menus.py @@ -1384,6 +1384,63 @@ def __init__(self, config, theme, parent): self.userlinkscheck.setChecked(self.config.disableUserLinks()) self.userlinkscheck.setVisible(False) + self.label_trusteddomains = QtWidgets.QLabel("Trusted image domains:") + self.list_trusteddomains = QtWidgets.QListWidget() + self.list_trusteddomains.addItems(parent.userprofile.getTrustedDomains()) + self.hbox_trusteddomains_buttons = QtWidgets.QHBoxLayout() + self.button_trusteddomains_add = QtWidgets.QPushButton("Add") + self.button_trusteddomains_remove = QtWidgets.QPushButton("Remove") + self.hbox_trusteddomains_buttons.addWidget(self.button_trusteddomains_add) + self.hbox_trusteddomains_buttons.addWidget(self.button_trusteddomains_remove) + self.label_trusteddomains_info = QtWidgets.QLabel( + "When an image link is sent in a conversation that belongs to one of these domains, pesterchum will embed the image alongside the message in the log" + ) + self.label_trusteddomains_info.setWordWrap(True) + + def _on_button_trusteddomains_remove_pressed(): + selected_idx = self.list_trusteddomains.currentRow() + if selected_idx >= 0: + self.list_trusteddomains.takeItem(selected_idx) + + def _on_button_trusteddomains_add_pressed(): + # When "add" is pressed, open a dialog where the user can enter 1 domain + schema = {"label": "Domain:", "inputname": "value"} + + result = MultiTextDialog("ENTER DOMAIN", self, schema).getText() + if result is None: + return + domain = result["value"] + + if not "." in domain: + # No TLD (.com, .org, etc) + # not a valid domain + errbox = QtWidgets.QMessageBox(self) + errbox.setText("Not a valid domain!") + errbox.setInformativeText( + "You are missing the TLD (.com, .org, etc etc)" + ) + errbox.exec() + return + + if not (domain.startswith("https://") or domain.startswith("http://")): + # Missing protocol, but thats fine + # This also means you'd need two entries for http & https version of a website + # but we stan https everywhere in this house so we ball + domain = "https://" + domain + if domain.count("/") < 3: + # append a '/' to the end if there is no '/' anywhere after the TLD + # this is to prevent something like `https://example.org` to also match with `https://example.org.mynefariouswebsite.com' + # IE, 'https://example.org' becomes 'https://example.org/', but 'https://example.org/beap' is left as-is + domain += "/" + self.list_trusteddomains.addItem(domain) + + self.button_trusteddomains_add.clicked.connect( + _on_button_trusteddomains_add_pressed + ) + self.button_trusteddomains_remove.clicked.connect( + _on_button_trusteddomains_remove_pressed + ) + # Will add ability to turn off groups later # self.groupscheck = QtGui.QCheckBox("Use Groups", self) # self.groupscheck.setChecked(self.config.useGroups()) @@ -1598,6 +1655,12 @@ def reset_themeBox(): layout_chat.addWidget(self.animationscheck) layout_chat.addWidget(animateLabel) layout_chat.addWidget(self.randomscheck) + + layout_chat.addWidget(self.label_trusteddomains) + layout_chat.addWidget(self.list_trusteddomains) + layout_chat.addLayout(self.hbox_trusteddomains_buttons) + layout_chat.addWidget(self.label_trusteddomains_info) + # Re-enable these when it's possible to disable User and Memo links # layout_chat.addWidget(hr) # layout_chat.addWidget(QtGui.QLabel("User and Memo Links")) diff --git a/parsetools.py b/parsetools.py index 983ff80a..d6880765 100644 --- a/parsetools.py +++ b/parsetools.py @@ -172,17 +172,23 @@ def convert(self, format): class embedlink(lexercon.Chunk): + domain_trusted = False + def __init__(self, url): self.url = url - print("GO FETCH ", url) - embeds.manager.fetch_embed(url) + self.domain_trusted = embeds.manager.check_trustlist(self.url) + if self.domain_trusted: + embeds.manager.fetch_embed(url) def convert(self, format): if format == "html": - return ( - "%s
%s" - % (self.url, self.url, self.url, self.url, self.url) - ) + if self.domain_trusted: + return ( + "%s
%s" + % (self.url, self.url, self.url, self.url, self.url) + ) + else: + return "%s" % (self.url, self.url) elif format == "bbcode": return f"[url]{self.url}[/url]" else: diff --git a/pesterchum.py b/pesterchum.py index 3f06ec41..cc2119e3 100755 --- a/pesterchum.py +++ b/pesterchum.py @@ -61,6 +61,7 @@ from randomer import RandomHandler, RANDNICK from toast import PesterToastMachine, PesterToast from scripts.services import SERVICES, CUSTOMBOTS, BOTNAMES, translate_nickserv_msg +import embeds try: from PyQt6 import QtCore, QtGui, QtWidgets, QtMultimedia @@ -1350,6 +1351,8 @@ def __init__(self, options, parent=None, app=None): self.move(100, 100) + embeds.manager.main_window = self ## We gotta get a reference to the user profile from somewhere since its not global. oh well + talk = QAction(self.theme["main/menus/client/talk"], self) self.talk = talk talk.triggered.connect(self.openChat) @@ -3059,6 +3062,15 @@ def updateOptions(self): self.config.set("time12Format", False) secondssetting = self.optionmenu.secondscheck.isChecked() self.config.set("showSeconds", secondssetting) + + # trusted domains + trusteddomains = [] + for i in range(self.optionmenu.list_trusteddomains.count()): + trusteddomains.append( + self.optionmenu.list_trusteddomains.item(i).text() + ) + self.userprofile.setTrustedDomains(trusteddomains) + # groups # groupssetting = self.optionmenu.groupscheck.isChecked() # self.config.set("useGroups", groupssetting) diff --git a/user_profile.py b/user_profile.py index 671b35fe..d2cf9f19 100644 --- a/user_profile.py +++ b/user_profile.py @@ -27,6 +27,18 @@ PchumLog = logging.getLogger("pchumLogger") +DEFAULT_EMBED_TRUSTLIST = [ + "https://cdn.discordapp.com/", + "https://pesterchum.xyz/", + "https://i.imgur.com/", + "https://media1.tenor.com/", + "https://raw.githubusercontent.com/", + "https://i.giphy.com/", + "https://64.media.tumblr.com/", + "https://i.redd.it/", +] + + class PesterLog: def __init__(self, handle, parent=None): global _datadir @@ -649,6 +661,7 @@ def __init__(self, user): else: self.mentions = [] self.autojoins = [] + self.trusted_domains = DEFAULT_EMBED_TRUSTLIST else: # Trying to fix: # IOError: [Errno 2] @@ -717,6 +730,9 @@ def __init__(self, user): self.userprofile["autojoins"] = [] self.autojoins = self.userprofile["autojoins"] + if "trusteddomains" not in self.userprofile: + self.userprofile["trusteddomains"] = DEFAULT_EMBED_TRUSTLIST + self.trusted_domains = self.userprofile["trusteddomains"] try: with open(_datadir + "passwd.js") as fp: self.passwd = json.load(fp) @@ -818,6 +834,14 @@ def setAutoJoins(self, autojoins): self.userprofile["autojoins"] = self.autojoins self.save() + def getTrustedDomains(self): + return self.trusted_domains + + def setTrustedDomains(self, trusted_domains): + self.trusted_domains = trusted_domains + self.userprofile["trusteddomains"] = self.trusted_domains + self.save() + def save(self): handle = self.chat.handle if handle[0:12] == "pesterClient": From f877f8fb9d9e4dd4beb224b7adda7680bc413231 Mon Sep 17 00:00:00 2001 From: anne Date: Wed, 25 Sep 2024 11:11:48 +0200 Subject: [PATCH 4/7] remove debug prints, fix some typos --- embeds.py | 5 +---- parsetools.py | 8 ++++---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/embeds.py b/embeds.py index a9bf37e3..0509c230 100644 --- a/embeds.py +++ b/embeds.py @@ -61,11 +61,8 @@ def has_embed(self, url): def check_trustlist(self, url): for item in self.main_window.config.userprofile.getTrustedDomains(): - print("~~", item) if url.startswith(item): - print("yurt") return True - print("nah") return False def fetch_embed(self, url, ignore_cache=False): @@ -73,7 +70,7 @@ def fetch_embed(self, url, ignore_cache=False): if not self.check_trustlist(url): PchumLog.warning( - "Requested embed fetch of %s denied because it does not match te trust filter.", + "Requested embed fetch of %s denied because it does not match the trust filter.", url, ) return diff --git a/parsetools.py b/parsetools.py index b996631a..c61626fc 100644 --- a/parsetools.py +++ b/parsetools.py @@ -182,7 +182,10 @@ def __init__(self, url): def convert(self, format): if format == "html": + # Only add the showable image tag if the domain is trusted & thus will actually be fetched + # Otherwise would show "fetching embed..." forever if self.domain_trusted: + # tag to make it clickable, tag to make it show the image (actual image resource is added after parsing) return ( "%s
%s" % (self.url, self.url, self.url, self.url, self.url) @@ -244,12 +247,9 @@ class imagelink(lexercon.Chunk): def __init__(self, string, img): self.string = string self.img = img - print("Imagelinmk: ", string, img) - # raise Exception(f'{string} {img}') def convert(self, format): # raise Exception(format) - print("TIME FOR ", format) if format == "html": return self.string elif format == "bbcode": @@ -294,7 +294,7 @@ def __init__(self, string): self.string = string def convert(self, format): - print("SMILEY:: ", format) + # print("SMILEY:: ", format) if format == "html": return "{}".format( smiledict[self.string], From b8983c137bf23d8160f5aedf1faaad303aeda951 Mon Sep 17 00:00:00 2001 From: mocha Date: Thu, 26 Sep 2024 22:10:04 +0200 Subject: [PATCH 5/7] some cleanup --- embeds.py | 12 +++++------- pesterchum.py | 5 ++++- user_profile.py | 5 +---- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/embeds.py b/embeds.py index 0509c230..f5f156e0 100644 --- a/embeds.py +++ b/embeds.py @@ -14,12 +14,10 @@ ## embeds.py # system for fetching & displaying image previews for image URLs -# has a single instance called `manager` at the bottom of this file +# has a single instance (singleton) called `manager` at the bottom of this file -## TODO: -## - add domain filters in settings -## - add "ignore filters" or whatever toggle in settings -## - *verify* domain filters +## TODO?: +## - add "ignore filters" or whatever toggle in settings. slight security risk (leaking IP) class EmbedsManager(QtCore.QObject): @@ -27,7 +25,7 @@ class EmbedsManager(QtCore.QObject): downloading = set() max_items = 50 - main_window = None + mainwindow = None embed_loading = QtCore.pyqtSignal(str) # when the get request starts (url: str) embed_loaded = QtCore.pyqtSignal( @@ -60,7 +58,7 @@ def has_embed(self, url): return url in self.cache def check_trustlist(self, url): - for item in self.main_window.config.userprofile.getTrustedDomains(): + for item in self.mainwindow.userprofile.getTrustedDomains(): if url.startswith(item): return True return False diff --git a/pesterchum.py b/pesterchum.py index 6f72e76e..9425c53a 100755 --- a/pesterchum.py +++ b/pesterchum.py @@ -1261,9 +1261,12 @@ def __init__(self, options, parent=None, app=None): # Part 1 :( try: if self.config.defaultprofile(): + # "defaultprofile" config setting is set + # load is here self.userprofile = userProfile(self.config.defaultprofile()) self.theme = self.userprofile.getTheme() else: + # Generate a new profile (likely this is the first-run) self.userprofile = userProfile( PesterProfile( "pesterClient%d" % (random.randint(100, 999)), @@ -1354,7 +1357,7 @@ def __init__(self, options, parent=None, app=None): self.move(100, 100) - embeds.manager.main_window = self ## We gotta get a reference to the user profile from somewhere since its not global. oh well + embeds.manager.mainwindow = self ## We gotta get a reference to the user profile from somewhere since its not global. oh well talk = QAction(self.theme["main/menus/client/talk"], self) self.talk = talk diff --git a/user_profile.py b/user_profile.py index 541ce7b7..a9246bce 100644 --- a/user_profile.py +++ b/user_profile.py @@ -268,10 +268,7 @@ def hideOfflineChums(self): return self.config.get("hideOfflineChums", False) def defaultprofile(self): - try: - return self.config["defaultprofile"] - except KeyError: - return None + return self.config.get("defaultprofile", None) def tabs(self): return self.config.get("tabs", True) From afbdadb6fb3e0f100a892c21ce2d3da867494da7 Mon Sep 17 00:00:00 2001 From: mocha Date: Thu, 3 Oct 2024 00:25:25 +0200 Subject: [PATCH 6/7] added gitlab default trust domain --- user_profile.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/user_profile.py b/user_profile.py index a9246bce..c0bc1dde 100644 --- a/user_profile.py +++ b/user_profile.py @@ -27,12 +27,13 @@ PchumLog = logging.getLogger("pchumLogger") -DEFAULT_EMBED_TRUSTLIST = [ +DEFAULT_EMBED_TRUSTLIST = [ # Default list of trusted image embed domains "https://cdn.discordapp.com/", "https://pesterchum.xyz/", "https://i.imgur.com/", "https://media1.tenor.com/", "https://raw.githubusercontent.com/", + "https://gitlab.com/", "https://i.giphy.com/", "https://64.media.tumblr.com/", "https://i.redd.it/", From e490ce7e2f3179cf406dff6a99ca27766c65982b Mon Sep 17 00:00:00 2001 From: mocha Date: Thu, 3 Oct 2024 00:26:02 +0200 Subject: [PATCH 7/7] forgets to run black epic style --- user_profile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_profile.py b/user_profile.py index c0bc1dde..aed73a01 100644 --- a/user_profile.py +++ b/user_profile.py @@ -27,7 +27,7 @@ PchumLog = logging.getLogger("pchumLogger") -DEFAULT_EMBED_TRUSTLIST = [ # Default list of trusted image embed domains +DEFAULT_EMBED_TRUSTLIST = [ # Default list of trusted image embed domains "https://cdn.discordapp.com/", "https://pesterchum.xyz/", "https://i.imgur.com/",